Training@USC Greedy Tino
思路:
DP题;
题意为给出n个橘子的重量,求其中最大的相等的和;
用dp[i][j]表示第i个橘子放入时,扁担两端的差为 j 时的最大重量(此重量为扁担重的那头的);
而橘子放入时,有四种可能:
1. 放入时,放入较轻的一端;
① 扁担两端的差大于橘子的重量,那么放入后,重的那端的重量还是不变;
dp[i][j-a[i]]=max{dp[i][j-a[i]],dp[i-1][j]};
② 扁担两端的差小于橘子的重量,那么放入后,轻的一端会变为重的一端;
dp[i][a[i]-j]=max{dp[i][j-a[i],dp[i-1][j]+a[i]-j};
2. 放入时,放入较重的一端;
dp[i][j+a[i]]=max{dp[i][j+a[i]],dp[i-1][j]+a[i]};
3. 不放入
dp[i][j]=max{dp[i][j],dp[i-1][j]};
要注意的是,有可能有橘子的重量为0的情况。这样的话,就可能扁担的一边可以放为0的橘子,一边可以不放东西也成立。
代码:
View Code
1 #include<iostream> 2 #include<string.h> 3 using namespace std; 4 int dp[105][2010]; 5 int a[105]; 6 int main(){ 7 int m; 8 cin>>m; 9 int times=0; 10 while(m--){ 11 times++; 12 int n; 13 cin>>n; 14 for(int i=0; i<n; i++){ 15 cin>>a[i]; 16 } 17 memset(dp, -1, sizeof(dp)); 18 // memset(dp,0,sizeof(dp)); 19 for(int k=0; k<n; k++) 20 dp[k][a[k]]=0; 21 for(int i=1; i<n; i++){ 22 for(int j=0; j<=2005; j++){ 23 if(dp[i-1][j] >= 0){ 24 if( dp[i][a[i]+j] < dp[i-1][j]){ 25 dp[i][a[i]+j] = dp[i-1][j]; 26 } 27 if(a[i] >= j){ 28 if(dp[i][a[i]-j] < dp[i-1][j] + j) 29 dp[i][a[i]-j] = dp[i-1][j]+j; 30 } 31 else if(a[i] < j){ 32 if(dp[i][j-a[i]] < dp[i-1][j] + a[i]) 33 dp[i][j-a[i]] = dp[i-1][j]+a[i]; 34 } 35 } 36 } 37 /* for(int g=0;g<2005;g++){ 38 dp[i][g]=dp[i-1][g]+a[i]; 39 } */ 40 for(int j=0; j<=2005; j++){ 41 if(dp[i][j] < dp[i-1][j]){ 42 dp[i][j] = dp[i-1][j]; 43 } 44 } 45 } 46 cout<<"Case "<<times<<": "; 47 // cout<<endl; 48 cout<<dp[n-1][0]<<endl; 49 } 50 // cin>>m; 51 return 0; 52 }