【POJ1015】Jury compromise 多個費用的背包
阿新 • • 發佈:2018-10-18
ise best parse || inline memory 最大 tor 題目
這是一道比較綜合的動態規劃問題。
首先,根據題目中的從N個人中選出M個人,並且要使得某個目標函數最優,可以想到是背包問題,且因為要取出M個人,人數也應該作為背包體積的一個維度。
其次,要求輸出路徑,因此不能進行滾動數組優化(優化後無法記錄狀態轉移途徑)。
再次觀察要求最優的函數,是一個相減取絕對值的函數,因此,可能出現負數,因此要給零點加一個偏移量。
狀態的選取:\(dp[i][j][k]\)表示前 i (階段)個物品中選取 j 個,且目標函數值為 k 時,和函數的最大值是多少。
代碼如下:
#include <iostream> #include <vector> #include <cstdio> #include <algorithm> #include <memory.h> #define cls(a,b) memset(a,b,sizeof(a)) using namespace std; const int maxn=201; const int maxm=21; const int maxdiff=801; int n,m,kase,d[maxn],p[maxn],mid,ans_p,ans_d; int dp[maxn][maxm][maxdiff],path[maxn][maxm][maxdiff]; std::vector<int> v; void init(){ cls(dp,0xcf);cls(path,0); v.clear(); ans_p=ans_d=0; } void read_and_parse(){ mid=m*20;//偏移量選取 for(int i=1;i<=n;i++) scanf("%d%d",&p[i],&d[i]); for(int i=0;i<=n;i++) dp[i][0][mid]=0; } void print(int i,int j,int k){//路徑處理 if(!j)return; int idx=path[i][j][k]; print(idx-1,j-1,k-(p[idx]-d[idx])); ans_d+=d[idx],ans_p+=p[idx]; v.push_back(idx); } void solve(){ for(int i=1;i<=n;i++){ int cost=p[i]-d[i],val=p[i]+d[i]; for(int j=1;j<=m;j++) for(int k=0;k<=mid<<1;k++){ dp[i][j][k]=dp[i-1][j][k]; path[i][j][k]=path[i-1][j][k]; if(k-cost>=0&&dp[i][j][k]<dp[i-1][j-1][k-cost]+val){ dp[i][j][k]=dp[i-1][j-1][k-cost]+val; path[i][j][k]=i; } } } int i,idx; for(i=0;i<=mid;i++) if(dp[n][m][mid-i]>=0||dp[n][m][mid+i]>=0) break; idx=(dp[n][m][mid-i]>dp[n][m][mid+i])?mid-i:mid+i;//比較和函數的大小 print(n,m,idx); printf("Jury #%d\n", ++kase); printf("Best jury has value %d for prosecution and value %d for defence:\n",ans_p,ans_d); for(i=0;i<v.size();i++)printf(" %d",v[i]); puts("\n"); } int main(){ while(scanf("%d%d",&n,&m)&&m+n){ init(); read_and_parse(); solve(); } return 0; }
【POJ1015】Jury compromise 多個費用的背包