• Hrbust 1541集合划分 & Hrbust 2002幂集【dp】


    Description
    对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的。举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,每个子集合的所有数字和是相等的:
    {3} 和 {1,2}
    这是唯一一种分法(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数) 如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分法的子集合各数字和是相等的:
    {1,6,7} 和 {2,3,4,5} {注 1+6+7=2+3+4+5}
    {2,5,7} 和 {1,3,4,6}
    {3,4,7} 和 {1,2,5,6}
    {1,2,4,7} 和 {3,5,6}
    给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。
    Input
    有多组测试数据。

    对于每组测试数据,输入一个整数n。

    Output
    对于每组测试数据,输出划分方案总数,如果不存在则输出0。
    Sample Input
    7
    Sample Output
    4

    **题解:**要把这些数分成两个求和后相等的集合,那么首先计算求和后的值,然后计算一个集合的求和是多少。

    可以发现,这是一个求方案数的动态规划【递推?】
    其实就是一个递推。。。。只有求和为0时方案数为1,一个数字0,求和值为j即用1到n每一个数加入到集合中时的方案数之和

    诶现在一看真是非常的简单了orz

    最后注意dp【half】结果其实是存在重复的,因为集合A是1 2 4 7 ,集合B是3 5 6与集合A是3 5 6 而集合B是1 2 4 7是一模一样的,要除2

    #include<stdio.h>
    #include<string.h>
    int main()
    {
        long long dp[600];
        int i,n,j;
        while(scanf("%d",&n)!=EOF)
        {
            memset(dp,0,sizeof(dp));
            int sum=n*(n+1)/2;///等差数列前n项求和公式
            int half=sum/2;
            if(sum%2!=0)///因为要把sum总和分成两个相等求和的集合,因此sum总和必须能被2整除否则一个方法也没有
            {
                printf("0
    ");
                continue;
            }
            dp[0]=1;///当输入0时肯定只有一种分法
            for(i=1;i<=n;i++)///dp第i个数字
            {
                for(j=half;j>=i;j--)
                {
                    dp[j]=dp[j]+dp[j-i];///达到每一个总和的方法,都是减去这个数所继承的上一个数的方法个数
                }
    //            for(int k=half;k>=0;k--)
    //            {
    //                printf("%d
    ",dp[k]);
    //            }
    //            printf("====
    ");
            }
            printf("%lld
    ",dp[half]/2);///此处算上的是两个集合交换位置,有重复的,要除2
        }
        return 0;
    }
    
    

    幂集
    Description
    所谓幂集,就是原集合中所有子集构成的集合,例如集合{1,2,3}的幂集为{{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3},{空集}}。现有一个元素个数为n的集合A={a1,a2,a3,a4…an},请求出集合A的幂集中有多少个 子集的和等于整数x。
    Input
    有多组测试数据处理到文件结束,每组数据第一行包含两个整数n(n<=30)和x(x>0);

    第二行有n个整数,0<ai<300,代表集合A中的元素。

    Output
    输出集合A的幂集中子集和为x的子集的个数。
    Sample Input
    5 6
    1 2 2 4 5
    3 7
    1 2 3

    Sample Output
    3
    0

    Hint
    第一组样例中{1,5},{2,4},{2,4}这三个子集的和都等于6,所以答案为3.

    **题解:**把这两题放一起因为是一样的,上一题中的背包容量是所有数求和的一半。这题中其实只需要求得集合内所有数能组成求和为多大的背包,即可像上一题一样得到用01背包计算每种求和的方法数,最后输出求和为x时的方法数,即是结果

    #include<stdio.h>///和1541的 集合划分 是一样的,把数字当一个物品,然后01背包
    #include<string.h>
    int main()
    {
        int a[39],i,j,x,n,dp[9005];///有30个数,每个数不超过300,dp的单位是数值大小,因此最大值是9000
        while(scanf("%d%d",&n,&x)!=EOF)
        {
            int sum=0;///这里所求的子集数量,其实就是所有元素能加和得到方法数
            for(i=0;i<n;i++)
            {
                scanf("%d",&a[i]);
                sum+=a[i];///求的最大dp值
            }
            memset(dp,0,sizeof(dp));///记得清空
            dp[0]=1;///当求和为0时,只有空集是这样的,所以只有1个子集(输入的元素大于0)
            for(i=0;i<n;i++)
            {
                for(j=sum;j>=a[i];j--)
                {
                    dp[j]=dp[j]+dp[j-a[i]];
                }
            }
            printf("%d
    ",dp[x]);///只需要当总和为x时的方法数
        }
        return 0;
    }
    
    
  • 相关阅读:
    左耳听风笔记之一
    富爸爸穷爸爸 -- 笔记
    Aruba无线控制器常用操作
    接入交换机办公网常用配置
    核心交换机办公网常用配置
    FortiGate防火墙办公网常用配置
    去掉深信服上网认证页面里的“修改密码”
    深信服上网行为管理短信认证多用户登录问题
    深信服上网行为管理配置跨三层MAC识别
    深信服上网行为管理实现一次认证成功之后连续3天无流量通过才再次认证
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135674.html
Copyright © 2020-2023  润新知