POJ 3093Margaritas on the River Walk 揹包DP
阿新 • • 發佈:2020-07-03
題目連結:http://poj.org/problem?id=3093
題目大意:給定一個容量為V(題目裡是D)的揹包和N(題目裡是V)件物品各自的體積,求有多少種方法使得揹包再也裝不下任何物品。
Sample Input
2 6 25 8 9 8 7 16 5 30 250 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Sample Output
1 15 2 16509438
假設所有物品按照從小到大排序,列舉剩下物品的最小體積,則前面的所有物品都被放入揹包,當前的揹包空餘為v-sum[i],而為了擠佔掉所列舉的物品的空間,那麼我們就需要最小體積為v-sum[i]-a[i]+1的物品,最大為v-sum[i]的物品。我們將這個範圍內的物品體積的方案數直接加到總的ans中就行了,接下來就是物品體積方案數的轉移,dp[j]表示空間為j的可以又幾個方向轉移過來。那麼dp[j]=d[j]+dp[j-a[i]]。
以下是AC程式碼:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int mac=1e3+10; int dp[mac],a[mac]; bool cmp(int x,int y){return x>y;} int main() { int t,n,m,test=0; scanf ("%d",&t); while (t--){ int tot=0; scanf ("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf ("%d",&a[i]),tot+=a[i]; sort(a+1,a+1+n,cmp); test++; if (a[n]>m) {printf("%d 0\n",test);continue;} memset(dp,0,sizeof dp); dp[0]=1; int ans=0; for (int i=1; i<=n; i++){//列舉剩下的最小a[i] tot-=a[i];//tot的當前值 int st=max(0,m-tot-a[i]+1);//m-tot,剩餘空間,不讓a[i]入包所需要佔據的最小空間 for (int j=st; j<=m-tot; j++)//佔據a[i]的空間 ans+=dp[j]; for (int j=m; j>=a[i]; j--)//空間為j的大小可以由幾個方向轉移過來 dp[j]+=dp[j-a[i]]; } printf("%d %d\n",test,ans); } return 0; }