暑假集訓開始了,按照隊裡的分配,我是弄dp的,嘛,於是我又一次的開始了從01揹包開始學習,昨天將杭電的幾道01揹包重新做了一遍,下面講講我自己對於01揹包的理解。
首先01揹包題目的雛形是
有n件物品和乙個容量為v的揹包。第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
從這個題目中可以看出,01揹包的特點就是:每種物品僅有一件,可以選擇放或不放。
其狀態轉移方程是:
f[i][v]=max
對於這方方程其實並不難理解,方程之中,現在需要放置的是第i件物品,這件物品的體積是c[i],價值是w[i],因此f[i-1][v]代表的就是不將這件物品放入揹包,而f[i-1][v-c[i]]+w[i]則是代表將第i件放入揹包之後的總價值,比較兩者的價值,得出最大的價值存入現在的揹包之中。
理解了這個方程後,將方程代入實際題目的應用之中,可得
for(i = 1; i<=n; i++)
}
理解了01揹包之後,下面就來看看實際的題目
hdu2546:飯卡
很經典的一道01揹包題,要注意的是這裡只要剩餘的錢不低於5元,就可以購買任何一件物品,所以5在這道題中是很特許的,再使用01揹包之前,我們首先要在現在所擁有的餘額中保留5元,用這五元去購買最貴的物品,而剩下的錢就是揹包的總容量,可以隨意使用,因此可得**
#include #include using namespace std;
int cmp(int a,int b)
}printf("%d\n",m+5-dp[m]-max);
}return 0;
}
hdu1171:big event in hdu
這道題咋看有點複雜,其實也只是換了一種思維,因為題目要求要盡量平均分配,所以我們可以先將總價值sum求出,然後得出其分配的平均值為sum/2,要注意這個答案可能為小數,但是又因為sum是整數,所以最後得出的sum/2是要小於等於實際的值。將這個結果進行01,揹包,可以得出其中乙個宿舍所得的最大價值,而另乙個宿舍的最大價值也可以相應的得到,而前者必定小於等於後者。
#include #include #include using namespace std;
int val[5005];
int dp[255555];
int main()
}printf("%d %d\n",sum-dp[sum/2],dp[sum/2]);
}return 0;
}
hdu2602:bone collector
經典的01揹包題,給出了石頭的數量與揹包的容量,然後分別給出每個石頭的容量與價值,要求最優解,經過前面的練手,這道題已經是很簡單了,可以說是01揹包果題。
#include #include #include using namespace std;
struct node
node[1005];
int main()
printf("%d\n",dp[m]);
}return 0;
}
hdu2639:bone collector ii(01揹包第k優解)
解決了上面那倒題目之後,這道題跟上面的題目有些不同,因為這裡要求的是第k優解
#include #include #include using namespace std;
struct node
node[1005];
int main()
,a[31],b[31];
scanf("%d%d%d",&n,&v,&k);
for(i = 0; i=node[i].val; j--)
int x,y,z;
x = y = z = 1;
a[d] = b[d] = -1;
while(z<=k && (x<=k || y<=k))//迴圈找出前k個的最優解
else
if(dp[j][z]!=dp[j][z-1])
z++;}}
}printf("%d\n",dp[v][k]);
}return 0;
}
hdu2955:robberies
這道題有點特別,咋看之下其狀態轉移方程似乎有些不同,但事實上遠離是相通的,要注意其精度
#include #include using namespace std;
struct bank
bank[10005];
int main()
}for(i = sum; i>=0; i--)}}
return 0;
}
hdu3466:proud merchants
這道題由於規定了手上的前低於q時就不能購買該樣東西,所以要先將商品按q-p排序,剩下的就是簡單的01揹包了
#include #include #include using namespace std;
struct node
a[555];
int cmp(node x,node y)//按q-p排序,保證差額最小為最優
}printf("%d\n",dp[m]);
}return 0;
}
hdu1864:最大報銷額
題目中藥注意的有幾樣,首先每張發票中單件物品**不能超過600,其次發票總額不能超過1000,而且發票上的物品必須是abc三類,將滿足以上條件的發票存入陣列之中,就是裸01揹包
#include #include #include using namespace std;
int dp[3000050];//由於每張發票不超過1000,最多30張,擴大100倍數後開這麼大即可
int main()
printf("%.2lf\n",dp[sum]/100.0);
}return 0;
}
恩,01揹包的專題就到這裡了,第一次說演算法,說得不咋樣,語言表達能力有限,各位看客求寬容啊!!!
揹包九講專題 01揹包
樸素2維無優化寫法 includeusing namespace std const int maxn 1e3 5 int dp maxn maxn v maxn w maxn intmain printf d n dp n m view code 優化1維寫法 關於優化是怎麼來的?首先為什麼第二個...
揹包 01揹包
01揹包 有n種物品與承重為m的揹包。每種物品只有一件,每個物品都有對應的重量weight i 與價值value i 求解如何裝包使得價值最大。dp i,v 表示前i個物體 包括第i個 面對容量為v的揹包的最大價值,c i 代表物體i的重量,w i 代表物體i的價值 如果第i個物體不放入揹包,則揹包...
揹包 01揹包,完全揹包,多重揹包
哈哈 01揹包 f i v max 完全揹包 f i v max 多重揹包 f i v max include include include include include define maxn 1000 using namespace std int n,cap int w maxn 重量 花...