暫存~dag 上的動態規劃(訓練指南—大白書)
2023年11月04日 16:42:48
閱讀數:1979
有向無環圖(dag,directed acyclic graph)上的動態規劃是學習動態規劃的基礎。很多問題都可以轉化為dag上的最長路、最短路或路徑計數問題。
一、矩形巢狀
題目描述:
有n個矩形,每個矩形可以用兩個整數a,b描述,表示它的長和寬。矩形x(a,b)可以巢狀在矩形y(c,d)中當且僅當ad(i) = max
其中e為邊集,最終答案為d(i).那如果要求輸出字典序最小的最長路徑呢?那麼必須找到第乙個最長的路徑的值然後遞迴輸出。
**:
[cpp]
view plain
copy
#include
#include
#include
#include
#include
using
namespace
std ;
const
intmx = 1000 + 10 ;
intn ;
intg[mx][mx],dp[mx] ;
struct
node
t[mx] ;
void
buildgraph()
// 建圖
intdag(
intx)
// 記憶化求解
return
ans ;
} void
print(
intx)
// 列印路徑
} intmain()
intans=1 ;
buildgraph() ;
memset(dp,-1,sizeof
(dp)) ;
for(
inti=0 ;i
for(int
i=0 ;i// 尋找第乙個點
if(dp[i]==ans)
} return
0 ;
}
二、硬幣問題
題目描述:
有n種硬幣,面值分別為v1,v2...,vn,每種都有無限多。給定非負整數s,可以選用多少個硬幣,使得面值之和恰好為s?輸出硬幣數目的最小值和最大值。0 <= n <= 100, 0 <= s <= 10000, 1 <= vi <= s。
解題思路:
本題的本質還是dag上的路徑問題。我們把每種面值看作乙個點,表示"還需要湊足的面值",則初始狀態為s,目標狀態為0。若當前的狀態i,每使用乙個硬幣j,狀態便轉移到i-vj。這個模型和巢狀矩形一題類似,但也有些明顯的不同之處:上題並沒有確定路徑的起點和終點(可以把任意矩形放在第乙個和最後乙個),而本題的起點必須是s,終點必須是0。把終點固定之後"最短路"才是有意義的。在巢狀矩形中,最短序列顯然是空(如果不允許空的話,就是單個矩形,不管怎樣都是平凡的),而本題的最短路徑卻不是那麼容易確定的。
接下來考慮"硬幣問題"。注意到最長路和最短路的求法是類似的,下面只考慮最長路。由於終點固定,d(i)的確切含義變為"從節點i出發到節點0的最長路徑長度"。
**:[cpp]
view plain
copy
#include
#include
#include
#define inf 1<<30
#define maxn 100+10
using
namespace
std ;
intv[maxn],n;
intmin[maxn],max[maxn];
inline
intmin(
inta,
intb)
//列印可行的方案
void
print_ans(
int* d,
ints)
} } int
main()
print_ans(min,s);
printf(" min\n"
);
print_ans(max,s);
printf(" max\n"
);
printf("min:%d max:%d\n"
,min[s],max[s]);
} return
0;
}
分析:本質上市乙個dag上的路徑問題,我們把每種面值看做乙個點,表示還需湊足的面值,則初始狀態為0,目標狀態為0,若當前在i,則每使用一枚硬幣j,狀態轉移到i-vj。
**:[cpp]
view plain
copy
#include
#define n 1100
intv[n],min[n],max[n],min_coins[n],max_coins[n];
void
print_ans(
int*d,
ints,
intn)
printf("\n"
);
} int
main()
for(i=1;i<=s;i++)
if(max[i]
max[i]=max[i-v[j]]+1;
max_coins[i]=j;
} //max[i]=max[i]>(max[i-v[j]]+1)?max[i]:(max[i-v[j]]+1);
} }
} printf("%d %d\n"
,min[s],max[s]);
print_ans(min_coins,s,n);
print_ans(max_coins,s,n);
} return
0;
}
上面的**中,如果不需要輸出路徑的話,則可以不要max_coins和min_coins陣列,下面在寫乙個遞迴的。
[cpp]
view plain
copy
#include
#include
#define n 1100
intv[n],d[n],vis[n];
intdp(
ints,
intn)
void
print_ans(
ints,
intn)
} }
intmain()
memset(vis,0,sizeof
(vis));
vis[0]=1;
d[0]=0;//終點狀態藥初始化為0,訪問過
ans=dp(s,n);
printf("%d\n"
,ans);
print_ans(s,n);
printf("\n"
);
} return
0;
}
只寫了求最長路徑的,如果要求最短路徑,則和最長路徑類似,在此省略。
DAG上的動態規劃
dag模型 有n個矩形,每個矩形用兩個整數a,b描述,表示長和寬,矩形 a,b 可以巢狀在矩形 c,d 中,當且僅當a小於c,b小於d或b小於c,a小於d。要解決的問題就是從眾多矩形中選出最多的矩形,使其可以按要求排成一列,若有多解,矩形編號的字典序要盡可能小。分析 按照書上的分析很簡單易懂,也容易...
DAG上的動態規劃
時間限制 3000 ms 記憶體限制 65535 kb 難度 4 描述 有n個矩形,每個矩形可以用a,b來描述,表示長和寬。矩形x a,b 可以巢狀在矩形y c,d 中當且僅當a 輸入 第一行是乙個正正數n 0輸出 每組測試資料都輸出乙個數,表示最多符合條件的矩形數目,每組輸出佔一行 樣例輸入 1 ...
DAG上的動態規劃
如需要課件ppt,聯絡我 dag 的定義 dag 意思是有向無環圖,所謂有向無環圖是指任意一條邊有方向,且不存在環路的圖。注 並非是一棵樹,邊數可以 經典例題 巢狀矩形 有n 個矩形,每個矩形可以用 ab來描述,表示長和寬。矩形 x ab 可以巢狀在矩形 y cd 中當且僅當 a或者b 相當於旋轉 ...