POJ1014-Dividing

转载请注明出处:優YoU  http://blog.csdn.net/lyy289065406/article/details/6661449

大致题意:

有分别价值为1,2,3,4,5,66种物品,输入6个数字,表示相应价值的物品的数量,问一下能不能将物品分成两份,是两份的总价值相等,其中一个物品不能切开,只能分给其中的某一方,当输入六个0是(即没有物品了),这程序结束,总物品的总个数不超过20000

 

输出:每个测试用例占三行:

           第一行: Collection #k: k为第几组测试用例

           第二行:是否能分(具体形式见用例)

           第三行:空白(必须注意,否则PE

 

解题思路:

有两种解决方法:

第一种是几乎百度上所有同学都热衷的多重背包,确实这题就是《背包九讲》里面的“多重背包”的应用题,直接套O(V*Σlog n[i])的模板就毫无悬念地AC了,《背包九讲》里面提供的是“多重背包+二进制优化”算法,百度上也有不少同学加入了自己的想法去进一步优化,例如利用“抽屉原理”证明并“取模优化”的可行性等,这些同学都做了不少功课,值得我们学习。

 

    第二种方法是几乎没有同学使用的DFS,本题用DFS也能0ms跑完,可能大家都被《背包九讲》冲昏了头脑,都想着套模板去了,但又看不懂模板。呻吟“研究了背包多长时间都不完全明白”的同学不妨试试DFS。其实本来不少DP题都可以用搜索过的,大家不要钻牛角尖。

 1 //Memory Time 
2 //452K 0MS
3
4 /*DFS*/
5
6 #include<iostream>
7 using namespace std;
8
9 int n[7]; //价值为i的物品的个数
10 int SumValue; //物品总价值
11 int HalfValue; //物品平分价值
12 bool flag; //标记是否能平分SumValue
13
14 void DFS(int value,int pre)
15 {
16 if(flag)
17 return;
18
19 if(value==HalfValue)
20 {
21 flag=true;
22 return;
23 }
24
25 for(int i=pre;i>=1;i--)
26 {
27 if(n[i])
28 {
29 if(value+i<=HalfValue)
30 {
31 n[i]--;
32 DFS(value+i,i);
33
34 if(flag)
35 break;
36 }
37 }
38 }
39 return;
40 }
41
42 int main(int i)
43 {
44 int test=1;
45 while(cin>>n[1]>>n[2]>>n[3]>>n[4]>>n[5]>>n[6])
46 {
47 SumValue=0; //物品总价值
48
49 for(i=1;i<=6;i++)
50 SumValue+=i*n[i];
51
52 if(SumValue==0)
53 break;
54
55 if(SumValue%2) //sum为奇数,无法平分
56 {
57 cout<<"Collection #"<<test++<<':'<<endl;
58 cout<<"Can't be divided."<<endl<<endl; //注意有空行
59 continue;
60 }
61
62 HalfValue=SumValue/2;
63 flag=false;
64
65 DFS(0,6);
66
67 if(flag)
68 {
69 cout<<"Collection #"<<test++<<':'<<endl;
70 cout<<"Can be divided."<<endl<<endl;
71 continue;
72 }
73 else
74 {
75 cout<<"Collection #"<<test++<<':'<<endl;
76 cout<<"Can't be divided."<<endl<<endl;
77 continue;
78 }
79 }
80 return 0;
81 }

==========华丽的分割线============

 

  1 //Memory Time 
2 //656K 16MS
3
4 /*多重背包+二进制优化*/
5
6 #include<iostream>
7 using namespace std;
8
9 int n[7]; //价值为i的物品的个数
10 int v; //背包容量
11 int SumValue; //物品总价值
12 bool flag; //标记是否能平分SumValue
13 int dp[100000]; //状态数组
14
15 int max(int a,int b)
16 {
17 return a>b?a:b;
18 }
19
20 /*完全背包*/
21 void CompletePack(int cost,int weight)
22 {
23 for(int i=cost;i<=v;i++)
24 {
25 dp[i]=max(dp[i],dp[i-cost]+weight);
26 if(dp[i]==v) //剪枝,当能够平分SumValue时退出
27 {
28 flag=true;
29 return;
30 }
31 }
32
33 return;
34 }
35
36 /*01背包*/
37 void ZeroOnePack(int cost,int weight)
38 {
39 for(int i=v;i>=cost;i--)
40 {
41 dp[i]=max(dp[i],dp[i-cost]+weight);
42 if(dp[i]==v) //剪枝
43 {
44 flag=true;
45 return;
46 }
47 }
48 return;
49 }
50
51 /*多重背包*/
52 void MultiplePack(int cost,int weight,int amount)
53 {
54 if(cost*amount>=v)
55 {
56 CompletePack(cost,weight);
57 return;
58 }
59
60 if(flag) //剪枝
61 return;
62
63 /*二进制优化*/
64 int k=1;
65 while(k<amount)
66 {
67 ZeroOnePack(k*cost,k*weight);
68
69 if(flag) //剪枝
70 return;
71
72 amount-=k;
73 k*=2;
74 }
75 ZeroOnePack(amount*cost,amount*weight);
76
77 return;
78 }
79
80 int main(int i)
81 {
82 int test=1;
83 while(cin>>n[1]>>n[2]>>n[3]>>n[4]>>n[5]>>n[6])
84 {
85 SumValue=0; //物品总价值
86
87 for(i=1;i<=6;i++)
88 SumValue+=i*n[i];
89
90 if(SumValue==0)
91 break;
92
93 if(SumValue%2) //sum为奇数,无法平分
94 {
95 cout<<"Collection #"<<test++<<':'<<endl;
96 cout<<"Can't be divided."<<endl<<endl; //注意有空行
97 continue;
98 }
99
100 v=SumValue/2;
101 memset(dp,-1,sizeof(dp));
102 dp[0]=0;
103 flag=false;
104
105 for(i=1;i<=6;i++)
106 {
107 MultiplePack(i,i,n[i]);
108
109 if(flag) //剪枝
110 break;
111 }
112
113 if(flag)
114 {
115 cout<<"Collection #"<<test++<<':'<<endl;
116 cout<<"Can be divided."<<endl<<endl;
117 continue;
118 }
119 else
120 {
121 cout<<"Collection #"<<test++<<':'<<endl;
122 cout<<"Can't be divided."<<endl<<endl;
123 continue;
124 }
125 }
126 return 0;
127 }

posted on 2011-08-04 23:19  小優YoU  阅读(1815)  评论(0编辑  收藏  举报

导航