zoukankan      html  css  js  c++  java
  • POJ1014Dividing

    转载请注明出处:優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 }
  • 相关阅读:
    vscode常用插件列表
    使用docker构建supervisor全步骤
    docker删除虚悬镜像(临时镜像文件)
    消息队列的对比
    ECharts使用:this.dom.getContext is not a function
    curl命令行请求
    工作工具清单
    《SQL优化入门》讲座总结
    初始化git库并配置自动部署
    php代码进行跨域请求处理
  • 原文地址:https://www.cnblogs.com/lyy289065406/p/2128033.html
Copyright © 2011-2022 走看看