想看更多的解题报告: http://iyenn.com/rec/1824570.html
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:
有六个大理石,他们的价值分别是1,2,3,4,5,6,然后分别给出六个大理石的个数,问如何平分给两个人,令两个人所得到的价值相等。
前面想到了DFS,写了一个裸的DFS,结果TLE,结果不断剪枝,还是TLE,后来觉得已经无法再剪枝了,但是却WE了,后来看了一位大神的,他的和我的只有一个地方不同,以下两段代码,我改了一个地方就A了,但是其实质上没什么区别,所以我认为这题用DFS还是不能过的。应该用DP是对的。
这是A了的:
- #include
- using namespace std;
-
- int a[7],sum;
-
- int dfs(int cap,int value){
- int i,temp;
-
- if(value==sum) return 1;
-
- for(i=cap;i>=1;i--)
- if(a[i]){
- temp=value+i;
- if(temp<=sum){
- a[i]--;
- if(dfs(i,temp)) return 1;
- }
- }
- return 0;
- }
-
- int main(){
- int flag,i,t;
- for(t=1;;t++){
- for(flag=sum=0,i=1;i<=6;i++){
- scanf("%d",&a[i]);
- sum+=i*a[i];
- if(!flag && a[i]) flag=1;
- }
-
- if(!flag) break;
-
- printf("Collection #%d:\n",t);
-
- if(sum&1){
- printf("Can't be divided.\n\n");
- continue;
- }
- sum=sum>>1;
- if(dfs(6,0))
- printf("Can be divided.\n\n");
- else
- printf("Can't be divided.\n\n");
- }
- return 0;
- }
这是WE的:
- #include
- using namespace std;
-
- int a[7],sum;
-
- int dfs(int cap,int value){
- int i,temp;
-
- if(value==sum) return 1;
-
- for(i=cap;i<=6;i++)
- if(a[i]){
- temp=value+i;
- if(temp<=sum){
- a[i]--;
- if(dfs(i,temp)) return 1;
- }
- }
- return 0;
- }
-
- int main(){
- int flag,i,t;
- for(t=1;;t++){
- for(flag=sum=0,i=1;i<=6;i++){
- scanf("%d",&a[i]);
- sum+=i*a[i];
- if(!flag && a[i]) flag=1;
- }
-
- if(!flag) break;
-
- printf("Collection #%d:\n",t);
-
- if(sum&1){
- printf("Can't be divided.\n\n");
- continue;
- }
- sum=sum>>1;
- if(dfs(1,0))
- printf("Can be divided.\n\n");
- else
- printf("Can't be divided.\n\n");
- }
- return 0;
- }
下面是模拟多重背包问题,总共6个物品,将第i个物品的价值与费用都看做是i,这样套用背包九讲的多重背包模板就可以了,不过注意的是数组要开的大一点.
- #include
- using namespace std;
- #define MAXV 100005
- #define INF 100000000
- #define max(a,b) a>b?a:b
-
- int sum,a[7],f[MAXV];
-
- void CompletePack(int cost,int weight){
- int i;
- for(i=cost;i<=sum;i++){
- f[i]=max(f[i],f[i-cost]+weight);
- }
- }
- void ZeroOnePack(int cost,int weight){
- int i;
- for(i=sum;i>=cost;i--){
- f[i]=max(f[i],f[i-cost]+weight);
- }
- }
-
- void MultiplePack(int cost,int weight,int amount){
- if(cost*amount>=sum){
- CompletePack(cost,weight);
- return ;
- }
- int k=1;
- while(k
- ZeroOnePack(k*cost,k*weight);
- amount-=k;
- k=k<<1;
- }
- ZeroOnePack(amount*cost,amount*weight);
- }
-
- void dp(){
- int i,j,k;
- for(i=1;i<=sum;i++) f[i]=-INF;
- f[0]=0;
- for(i=1;i<=6;i++)
- MultiplePack(i,i,a[i]);
- }
-
- int main(){
- int flag,i,t;
- for(t=1;;t++){
- for(flag=sum=0,i=1;i<=6;i++){
- scanf("%d",&a[i]);
- sum+=i*a[i];
- if(!flag && a[i]) flag=1;
- }
-
- if(!flag) break;
-
- printf("Collection #%d:\n",t);
-
- if(sum&1){
- printf("Can't be divided.\n\n");
- continue;
- }
- sum=sum>>1;
- dp();
- if(f[sum]>=0)
- printf("Can be divided.\n\n");
- else
- printf("Can't be divided.\n\n");
- }
- return 0;
- }
上面是用“拆分法”来做的,不过应为题目是一个可行性问题,即状态只有两种,是否可行,现在用一种O(VN)的算法来写,上面O(V*∑logn[i])跑了16MS,现在用这种算法只跑了0MS。或许是这题的数据太弱了吧。
- #include
- using namespace std;
- #define MAXV 100005
- #define INF 100000000
- #define max(a,b) a>b?a:b
-
- int sum,a[7],ans,f[MAXV],t[MAXV];
-
- void dp(){
- int i,j,k;
- memset(f,0,sizeof(f)); //用1表示可行,0表示不行
- f[0]=1;
- for(i=1;i<=6;i++){
- memset(t,0,sizeof(t));
- for(j=i;j<=sum;j++){
- if(!f[j] && f[j-i] && t[j-i]+1<=a[i]){
- f[j]=1;
- t[j]=t[j-i]+1;
- }
- }
- }
- }
-
- int main(){
- int flag,i,t;
- for(t=1;;t++){
- for(flag=sum=0,i=1;i<=6;i++){
- scanf("%d",&a[i]);
- sum+=i*a[i];
- if(!flag && a[i]) flag=1;
- }
-
- if(!flag) break;
-
- printf("Collection #%d:\n",t);
-
- if(sum&1){
- printf("Can't be divided.\n\n");
- continue;
- }
- sum=sum>>1;
- dp();
- if(f[sum])
- printf("Can be divided.\n\n");
- else
- printf("Can't be divided.\n\n");
- }
- return 0;
- }
评论记录:
回复评论: