动态规划(冬令营课堂笔记)
簡單問題
01背包
012背包
部分背包
機(jī)器分配
烽火傳遞
花店櫥窗問題
簡單問題
01背包
一個(gè)容量為m的背包,有n個(gè)物品,第i個(gè)物品的體積為wi,價(jià)值為ci。選擇若干物品,使得體積總和不超過m的情況下價(jià)值總和最大。
n<=100,m<=10000。
?
搜索? 復(fù)雜度為2^n
void dfs(int x,int y,int z)//當(dāng)前物品編號,當(dāng)前容量,當(dāng)前價(jià)值 {if(x==n+1){if(y<m)ans=max(ans,z);return;}dfs(x+1,y+w[x],z+c[i]);dfs(x+1,y,z); }如果前兩維相同,只需選擇第三維的最大值
小小的變形
const int INF=0x7f; int dfs(int x,int y) {int ans;if(x==n+1){if(y>m)return -INF;return 0;}ans=max(dfs(x+1,y+w[x])+c[x],dfs(x+1,y));return ans; } dfs(1,0);加一個(gè)數(shù)組記錄
const int INF=0x7f; int dfs(int x,int y) {if(x==n+1){if(y>m)return -INF;return 0;}dp[x][y]=max(dfs(x+1,y+w[x])+c[x],dfs(x+1,y));return dp[x][y]; } dfs(1,0);應(yīng)用記錄狀態(tài)? 記憶化搜索 n*m
const int INF=0x7f; int dfs(int x,int y) {if(y>m)return -INF;if(x==n+1){return 0;}if(dp[x+1][y+w[x]]) //選該物品 dp[x][y]=max(dp[x+1][y+w[x]]+c[x],dp[x][y]);elsedp[x][y]=max(dfs(x+1,y+w[x])+c[x],dp[x][y]); if(dp[x+1][y]) //不選該物品 dp[x][y]=max(dp[x+1][y]+c[x],dp[x][y]);elsedp[x][y]=max(dfs(x+1,y))+c[x],dp[x][y]); return dp[x][y]; } dfs(1,0);遞歸變遞推
先寫出搜索
最大/最小值 存放到數(shù)組中
后面遞歸該狀態(tài)時(shí) 直接使用數(shù)組中的值來代替
O(dfs里的狀態(tài)個(gè)數(shù)*轉(zhuǎn)移的時(shí)間復(fù)雜度)
?
找邊界
找遞推方法(順序還是逆序)
轉(zhuǎn)移(推轉(zhuǎn)移方程)
搜索->記憶化搜索->遞歸變遞推
for(int i=n;i>=1;i--)for(int j=0;j<=m;j++)dp[i][j]=max(dp[i+1][j],dp[i+1][j+w[i]]+c[i]); ans=dp[1][0]012背包
一個(gè)容量為m的背包,有n個(gè)物品,第i個(gè)物品的體積為wi,價(jià)值為ci,有2個(gè)。
選擇若干物品,使得體積總和不超過m的情況下價(jià)值總和最大。
記憶化搜索
const int INF=0x7f; int dfs(int x,int y,int z) {if(x==n+1){if(y<m)ans=max(ans,z);return -INF;}if(dp[x+1][y]) //一個(gè)都不選 dp[x][y]=max(dp[x][y],dp[x+1][y]);elsedp[x][y]=max(dp[x][y],dfs(x+1,y));if(dp[x+1][y+w[x]]) //選一個(gè) dp[x][y]=max(dp[x][y],dp[x+1][y+w[x]])+c[x]);elsedp[x][y]=max(dp[x][y],dfs(x+1,y+w[x])+c[x]);if(dp[x+1][y+w[x]]) //選兩個(gè) dp[x][y]=max(dp[x][y],dp[x+1][y+2*w[x]])+2*c[x]);elsedp[x][y]=max(dp[x][y],dfs(x+1,y+2*w[x])+2*c[x]);return dp[x][y]; } dfs(1,0);部分背包
一個(gè)容量為m的背包,有n個(gè)物品,第i個(gè)物品的體積為wi,價(jià)值為ci,有ki個(gè)。
選擇若干物品,使得體積總和不超過m的情況下價(jià)值總和最大。
記憶化搜索
int dfs(int x,int y) {if (y>m) return -INF;if (x==n+1) return 0;for (int i=0; i<=k[x]; i++){if (dp[x+1][y+i*w[x]])dp[x][y]=max(dp[x][y],dp[x+1][y+i*w[x]]+c[x]);elsedp[x][y]=max(dp[x][y],dfs(x+1,y+i*w[x])+i*c[x]);}return dp[x][y]; } dfs(1,0);遞推
for (i=n; i>=1; i--)for (j=0; j<=m; j++)for (l=0; l<=k[i]; l++)dp[i][j]=max(dp[i][j],dp[i+1][j+l*w[i]]+l*c[i]); dp[1][0]機(jī)器分配
有n家店,每家店都有m臺機(jī)器,第i家店購買j臺機(jī)器花費(fèi)a[i][j]元(可能存在a[i][j]>a[i][j+1]),要購買總共m臺機(jī)器,求最小花費(fèi)。
搜索
//機(jī)器分配 dfs(int x,int y,int z) {if(y>m)return;if(x==n+1){if(y==n+1)ans=min(ans,z);return;}for(int i=0;i<=m;i++)dfs(x+1;y+i,z+a[x][i]); } dfs(1,0,0);小小的變形
//機(jī)器分配 int dfs(int x,int y) {if(y>m)return -INF;if(x==n+1){if(y==m)return 0;//再也不需要買機(jī)器 return -INF;}for(int i=0;i<=m;i++)dp[x][y]=min(dp[x][y],dfs(x+1,y+i)+a[x][i]);return dp[x][y]; } dfs(1,0);記憶化搜索
//機(jī)器分配 int dfs(int x,int y) {if(y>m)return -INF;if(x==n+1){if(y==m)return 0;//再也不需要買機(jī)器 return -INF;}for(int i=0;i<=m;i++)if(dp[x+1][y+i])dp[x][y]=min(dp[x][y],dp[x+1][y+i]+a[x][i]);elsedp[x][y]=min(dp[x][y],dfs(x+1,y+i)+a[x][i]);return dp[x][y]; } dfs(1,0);遞推
for(int i=n;i>=1;i--)for(int j=0;j<=m;j++){dp[i][j]=INF;for(k=0;k<=m-j;k++)dp[i][j]=min(dp[i][j],dp[i+1][j+k]+a[i][k]);} ans=dp[1][0]烽火傳遞
給定n個(gè)非負(fù)整數(shù),選擇其中若干數(shù)字,使得每連續(xù)k個(gè)數(shù)中至少有一個(gè)數(shù)被選出。
要求選擇的數(shù)字之和盡可能小。
搜索
void dfs(int x,int y) {if(x==n+1){ans=min(ans,y);return;}for(int i=x+1;i<=min(n+1,x+k);i++)dfs(i,y+a[i]);//i是下一個(gè) } dfs(0,0);記憶化
int dfs(int x) {if(x==n+1)return 0;dp[x]=INF;for(int i=x+1;i<=min(n+1,x+k);i++)if(dp[i])dp[x]=min(dp[x],dp[i]+a[i]);elsedp[x]=min(dp[x],dfs(i)+a[i]);return dp[x]; } dfs(0);遞推
/*dp[n+1]=0; dp[1] dp[2] dp[3] .. dp[1+k]*/for (i=n; i>=0; i--) {dp[i]=INF;for (int j=i+1; j<=min(n+1,i+k); j++)dp[i]=min(dp[i],dp[j]+a[j]); } dp[0]花店櫥窗問題
給定一個(gè)n*m的矩陣A(n<=m),求一個(gè)序列a1,a2,…,an滿足1<=a1<a2<…<an<=m。使得A[1][a1]+A[2][a2]+…+A[n][an]最大。A可能有負(fù)數(shù)。
搜索
void dfs(int x,int y,int z) {if(x==n+1){if(y==m+1)ans=max(ans,z);return;}for(int i=y+1;i<=m;i++)dfs(x+1,i,z+a[x+1][i]); } dfs(0,0,0);記憶化搜索
int dfs(int x,int y) {if(x==n+1){if(y==m+1)return 0;else return -INF;}for(int i=y+1;i<=m;i++){if(dp[x+1][i])dp[x][y]=max(dp[x][y],dp[x+1][i]+a[x+1][i]);elsedp[x][y]=max(dp[x][y],dfs(x+1,i)+a[x+1][i]);return dp[x][y];} } dfs(0,0);遞推
/*dp[n+1][m+1]=0; dp[n+1][0~m]=-INF; dp[1][] dp[2][] dp[3][]*/ for (i=n; i>=0;i--)for (j=0; j<=m+1; j++)for (k=j+1; k<=m+1; k++)dp[i][j]=max(dp[i][j],dp[i+1][k]+a[i+1][k]); cout<<dp[0][0];?
轉(zhuǎn)載于:https://www.cnblogs.com/thmyl/p/7359328.html
總結(jié)
以上是生活随笔為你收集整理的动态规划(冬令营课堂笔记)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 8、jeecg 笔记之 自定义word
- 下一篇: Android ViewPager指示器