zoukankan      html  css  js  c++  java
  • Hdu 1709 The Balance

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1709

    题意:

         给N个整数,每个数只能使用一次。将他们组合起来,最后看在1~sum(a[1]..a[N])这些数里有多少数是这N个数组合不出来的.

         先输出这些数的个数,再将这些数输出来。如果个数是0,那么不需要输出数。 

         案例分析:

         input:

         3

         1 2 4

         output:

         0

         -->1(||4-1-2) , 2(||4-2) , 1+2(||4-1) , 4  , 1+4 , 2+4 , 1+2+4.

    思路分析:

         可以将这N个数看成是N个物品。就将这个问题转化成了一个0-1背包问题,那么,所有的加法组合就可以求出来。那么减法呢?

         依旧是上面的案例,由于这组案例比较特殊。 只需加法组合便可以将1~sum(a[1]..a[N])全部组合出来.不过并不妨碍分析减法组合过程。

         0-1背包解法得到的加法组合必然是一个以上物品组合起来的(这个是无需置疑的),那么减法无非是减少组合的物品个数

         如 (4+1)-1=4 --> 4+1的组合减去1的组合 得到了一个新的组合。

         看第二个案例或许更明白:

         3

         9 2 1

         先将加法组合用0-1背包解出来:

         1 , 2 , 1+2 , 9 , 1+9 , 2+9 , 1+2+9 .

         这是所有的加法组合,接下来利用加法求减法组合。

         2-1=1 , (1+2)-1=2 , 9-1=8 , (1+9)-1=9 , (2+9)-1=10 , (1+2+9)-1=11.

         (1+2)-1=2 , 9-2=7 , (1+9)-2=8 , (2+9)-2=9 , (1+2+9)-2=10.

         9-(1+2)=6 , (9+1)-(1+2)=7 , (2+9)-(1+2)=8 , (1+2+9)-(1+2)=9.

         ...

         ...

         最后所有的减法都暴力扫完之后,发现 4和5这两个数字是组合不出来的。

         所以答案便是 2 个数 4和5 了。

    代码如下:

         

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 #define MAX 101
     7 int w[MAX*MAX],c[MAX*MAX];//w->价值,c->所需空间花费;
     8 bool flag[MAX*MAX];
     9 int f[MAX*MAX];
    10 int x[MAX*MAX];
    11 int p[MAX*MAX];
    12 int n,v,ans;
    13 void init()
    14 {
    15     memset(w,0,sizeof(w));
    16     memset(c,0,sizeof(c));
    17     memset(f,0,sizeof(f));
    18     memset(p,0,sizeof(p));
    19     memset(x,0,sizeof(x));
    20     memset(flag,false,sizeof(flag));
    21     v=0;
    22     ans=0;
    23 }
    24 void out()
    25 {
    26     for(int i=0;i<=v;i++)
    27         cout<<f[i]<<" ";
    28     cout<<endl;
    29 }
    30 void read()//初始化物品信息;
    31 {
    32     int i;
    33     for(i=1;i<=n;i++)
    34     {
    35         scanf("%d",&w[i]);
    36         c[i]=w[i];
    37         v+=w[i];
    38     }
    39 }
    40 void cal()
    41 {
    42     int i,j;
    43     int k=0;
    44     for(i=1;i<=n;i++)//0-1背包 遍历所有加法可能
    45         for(j=v;j>=c[i];j--)
    46         {
    47             if(f[j]>=0) flag[f[j]]=true;
    48             f[j]=max(f[j],f[j-c[i]]+w[i]);
    49             if(f[j]>=0) flag[f[j]]=true;
    50         }
    51     //out();
    52     for(i=0;i<=v;i++)//找出所有加法组合;
    53         if(flag[i]) x[k++]=i;
    54 
    55     for(i=0;i<k;i++)//暴力找出可能的减法组合;
    56         for(j=i+1;j<k;j++)
    57             if(x[j]-x[i]>=0) flag[x[j]-x[i]]=true;
    58 
    59     for(i=0;i<=v;i++)
    60         if(!flag[i]) p[ans++]=i;
    61 
    62     printf("%d
    ",ans);
    63     if(!ans) return ;
    64     for(i=0;i<ans;i++)
    65         printf(i==ans-1?"%d
    ":"%d ",p[i]);
    66 }
    67 void solve()
    68 {
    69     init();
    70     read();
    71     cal();
    72 }
    73 
    74 int main()
    75 {
    76     while(scanf("%d",&n)!=EOF)
    77     {
    78         solve();
    79     }
    80     return 0;
    81 }
    View Code

         还有一种常见的方法便是母函数~~

         是不是很像呢. 把这n个数看成是n克的砝码,每个砝码只有一个

         母函数的思路就不赘诉了 , 不知道的朋友可以百度学习一下。

         这里需要改动一点点的便是:在合并的过程中加入减法合并。

         只是需要注意 每个砝码只有一个。

    代码如下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 #define MAX 101
     7 int num[MAX];
     8 int c1[MAX*MAX];
     9 int c2[MAX*MAX];
    10 int ans[MAX*MAX];
    11 int n,sum;
    12 void init()
    13 {
    14     sum=0;
    15     memset(c1,0,sizeof(c1));
    16     memset(c2,0,sizeof(c2));
    17 }
    18 void read()
    19 {
    20     for(int i=1;i<=n;i++)
    21     {
    22         scanf("%d",&num[i]);
    23         sum+=num[i];
    24     }
    25 }
    26 void cal()
    27 {
    28     int i,j,k;
    29     int count=0;
    30     c1[0]=c1[num[1]]=1;
    31     for(i=2;i<=n;i++)
    32     {
    33         for(j=0;j<=sum;j++)
    34             for(k=0;k+j<=sum&&k<=num[i];k+=num[i])
    35             {
    36                 if(j>=k) c2[j-k]+=c1[j];
    37                 else c2[k-j]+=c1[j];
    38                 c2[j+k]+=c1[j];
    39             }
    40         for(j=0;j<=sum;j++)
    41         {
    42             c1[j]=c2[j];
    43             c2[j]=0;
    44         }
    45     }
    46     for(i=1;i<=sum;i++)
    47     {
    48         if(!c1[i])
    49         {
    50             ans[count++]=i;
    51         }
    52     }
    53     printf("%d
    ",count);
    54     if(!count) return ;
    55     for(i=0;i<count;i++)
    56         printf(i==count-1?"%d
    ":"%d ",ans[i]);
    57 }
    58 void solve()
    59 {
    60     init();
    61     read();
    62     cal();
    63 }
    64 
    65 int main()
    66 {
    67     while(scanf("%d",&n)!=EOF)
    68     {
    69         solve();
    70     }
    71     return 0;
    72 }
    View Code
  • 相关阅读:
    性能测试七:jmeter进阶之文件上传下载、定时器
    性能测试六:jmeter进阶之Cookie与header管理器
    导出文本、表格、图像到PDF格式文件中(学习整理)
    数据库(学习整理)----7--Oracle多表查询,三种join连接
    反射(学习整理)----Class类和加载器ClassLoader类的整理
    反射(学习整理)----操作类、属性、方法!
    数据库(学习整理)----6--Oracle如何快速备份和多次备份数表数据
    数据库(学习整理)----5--Oracle常用的组函数
    数据库(学习整理)----4--Oracle数据查询(基础点1)
    Java小例子(学习整理)-----学生管理系统-控制台版
  • 原文地址:https://www.cnblogs.com/By-ruoyu/p/3913494.html
Copyright © 2011-2022 走看看