程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu3466 Proud Merchants 變形的0-1背包

hdu3466 Proud Merchants 變形的0-1背包

編輯:C++入門知識

   這道題看了解題報告後才懂的,第一次遇到這種變形的背包,不過真是很難想到要先按照Q-P排序。。。   下面說一下我對本題的理解。        首先講一下暴力解決,很顯然我們可以用枚舉的方法,對每個物品都有選與不選兩種決策。但即使暴力也存在一個問題,比如對 3 5 6,5 10 5這兩個物品,如果我們的決策是兩個都不選或者是只選其中一個,顯然沒什麼問題,但如果我們要是兩個都選的話,按照之前這個順序有m>=13,但如果把兩個的順序交換一下則m>=10即可,從這裡就可以看出問題的所在了。於是,對任意兩個物品i,j,為了避免上面存在的那種問題,我們可以算出兩種順序所需要的最少金額,若i->j,則至少需要Pi+Qj,若是j->i則至少需要Pj+Qi。如果已知結果是i->j較優的話,則有Pi+Qj<Pj+Qi,即Qi-Pi>Qj-Pj。所以若對之前的物品先按照Q-P由大到小排好序後,然後暴力就可以解決了。但這種暴力其實已有較好的算法可以解決了,即0-1背包,說到這裡原問題就已經完全轉化為了普通的0-1背包了       但還有一點需要要解釋一下,剛才是說暴力是按照Q-P從大到小先排好序,但由於dp與暴力其實正好是兩個逆過程,dp的好處就不再多解釋了,即避免對子問題的重復計算。所以dp前我們是按照Q-P從小到大的順序排好序。   OK,此題總算完滿解決了!   [cpp]   #include<iostream>   #include<cstdio>   #include<cstring>   #include<algorithm>      using namespace std;   struct goods   {       int p,q,v,d;       bool operator<(const goods t)const       {           return d<t.d;       }   }g[501];   int dp[5001];      int main()   {       int n,m,i,j;       while(~scanf("%d%d",&n,&m))       {           memset(dp,0,sizeof(dp));           for(i=1;i<=n;i++)           {               scanf("%d%d%d",&g[i].p,&g[i].q,&g[i].v);               g[i].d=g[i].q-g[i].p;           }           sort(g+1,g+n+1);           for(i=1;i<=n;i++)               for(j=m;j>=g[i].q;j--)                   dp[j]=max(dp[j],dp[j-g[i].p]+g[i].v);           printf("%d\n",dp[m]);       }       return 0;   }      

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved