有N堆石子。现将它们分成两个组A,B。 每组有N/2堆石子 要求两个组的石子数相接近越好。
输入
每组测试数据第一行一个整数n,n为偶数且小于100 第二行n个整数分别给出每堆石子的石子数字,所有石子总和不超过2000
输出
输出A,B两组的最小差值。
样例
输入复制
6
7 9 2 6 4 2
输出复制
0
三维的,注意第二个循环一定要逆循环。新算出来的状态不能参加后面的运算。
#include<bits/stdc++.h> using namespace std; bool f[200][101][2001]; int n,a[101]; int abbs(int x,int y) { if(x-y>0) return x-y; else return y-x; } int main() { cin>>n; int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; } memset(f,0,sizeof(f)); f[0][0][0]=1; for(int i=1;i<=n;i++) for(int j=n;j>=0;j--) //所使用的数字个数 // for(int k=2000;k>=0;k--) // for (int j=0;j<=n;j++) for (int k=0;k<=2000;k++) //构成的总和 { f[i][j][k]=f[i-1][j][k]; if(f[i-1][j][k]==1) f[i][j+1][k+a[i]]=1; } int ans=sum; for(int i=0;i<=sum;i++) if(f[n][n/2][i]==1) { // cout<<i<<" is "<<endl; if(ans>abbs(i,sum-i)) { ans=abbs(i,sum-i); } } cout<<ans<<endl; return 0; }
#include<bits/stdc++.h> using namespace std; bool f[200][101][2001]; int n,a[101]; int abbs(int x,int y) { if(x-y>0) return x-y; else return y-x; } int main() { cin>>n; int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; } memset(f,0,sizeof(f)); f[0][0][0]=1; for(int i=1;i<=n;i++) for(int k=2000;k>=0;k--) //所构成的总和 for(int j=0;j<=n;j++) //所使用的数字个数 { f[i][j][k]=f[i-1][j][k]; if(f[i-1][j][k]==1) f[i][j+1][k+a[i]]=1; } int ans=sum; for(int i=0;i<=sum;i++) if(f[n][n/2][i]==1) { // cout<<i<<" is "<<endl; if(ans>abbs(i,sum-i)) { ans=abbs(i,sum-i); } } cout<<ans<<endl; return 0; }
二维的程序
#include<bits/stdc++.h> using namespace std; bool f[101][2001]; int n,a[101]; int abbs(int x,int y) { if(x-y>0) return x-y; else return y-x; } int main() { cin>>n; int sum=0; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); sum+=a[i]; } memset(f,0,sizeof(f)); f[0][0]=1; for(int i=1;i<=n;i++) for(int k=2000;k>=0;k--) for(int j=n;j>=0;j--) if(f[j][k]==1) f[j+1][k+a[i]]=1; int ans=sum; for(int i=0;i<=sum;i++) if(f[n/2][i]==1) { if(ans>abbs(i,sum-i)) { ans=abbs(i,sum-i); } } cout<<ans<<endl; return 0; }
分石子3
给你N个数字,当然不是每个数字你均需要用到,现将这些数字分成两部份
其总和是相等的。问这个值最大能到多少?如果不能分成相等的两份就输出"Sorry"
输入
第一个数字N(100以内)代表数字的个数.
接下来N个数代表每个数字.所有数字的总和不超过2000
输出
如题所示
样例
输入复制
4
11 11 11 11
输出复制
22
#include<bits/stdc++.h> using namespace std; int main() { int n,s[101],f[111][3001],sum=0; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&s[i]),sum+=s[i]; sum/=2; memset(f,-1,sizeof(f)); f[0][0]=0; //f[i,j]表示用前i个数字,两塔高度差为j时,矮的塔的高多为多少 for(int i=1;i<=n;i++)//枚举数字,可以不选,所以从0开始 for(int j=0;j<=sum;j++) //枚举两者的高度差 if(f[i-1][j]>=0) { f[i][j]=max(f[i][j],f[i-1][j]); //这个数字不用 f[i][s[i]+j]=max(f[i][s[i]+j],f[i-1][j]); //将数字放在高塔上,高度差增加,矮塔高度不变 if(s[i]>j)//将数字放在矮塔上,高矮关系发生改变 ,新矮塔高度增加j f[i][s[i]-j]=max(f[i][s[i]-j],j+f[i-1][j]); else //将数字放在矮塔上,高矮关系不变,原矮塔高度增加s[i] f[i][j-s[i]]=max(f[i-1][j]+s[i],f[i][j-s[i]]); } if(f[n][0]) printf("%d",f[n][0]); else printf("Sorry"); }
1778506 2006-04-19 14:42:00 Accepted 2059 FPC 00:00.17 424K 我微笑不代表我快乐 program zju2059; var h,s:array[0..100] of integer; f,f1:array[0..2000] of integer; n,i,j:longint; begin while true do begin read(n); if n=-1 then halt; s[0]:=0; for i:=1 to n do begin read(h[i]); s[i]:=s[i-1]+h[i]; end; for j:=1 to s[n] do f1[j]:=-1; f1[0]:=0; f1[h[1]]:=h[1]; //f1[i]代表二个Twin之间高度差为i时,较高的Twin的高度为F1[i] f:=f1; for i:=1 to n-1 do begin for j:=0 to s[i] do if f1[j]>-1 then begin if f1[j]+h[i+1]>f[j+h[i+1]] then //将当前Stone放到二个Twin中较高的那个上面,这个条件是不能去掉的! f[j+h[i+1]]:=f1[j]+h[i+1]; if h[i+1]<=j then //将当前的Stone放到较矮的Twin上去,这样要分二种情况讨论一下,因为放上去后,有可能会影响 //到二个Twin之间的高矮关系,当h[i+1]<j时,说明放到矮的Twin上,高矮关系不会变化 begin if f1[j]>f[j-h[i+1]] then f[j-h[i+1]]:=f1[j] end else if f1[j]-j+h[i+1]>f[h[i+1]-j] then //f1[j]-j代表从前矮Twin的高度,因为f1[j]代表高度差为J时,高Twin的高度,于是矮Twin的高度就应该为 //f1[j]-j,现在将Stone放到矮Twin上,并且放上去后,影响了高矮Twin之间的关系,从前高的变成了矮的 //矮的变成了高的.于是放上去后新的高Twin的高度为F1[j]-j+H[i+1]. f[h[i+1]-j]:=f1[j]-j+h[i+1] end; f1:=f; end; if n=0 then writeln('Sorry') else if f[0]>0 then writeln(f[0]) else writeln('Sorry'); end; end.