zoukankan      html  css  js  c++  java
  • 94.子集和 (10分)

    C时间限制:1 毫秒 |  C内存限制:65535 Kb
    题目内容:
     对于由从1到N(1<=N<=39)这N个连续的整数组成的集合来说,我们有时可以将集合分成两个部分和相同的子集合。
    例如,N=3时,可以将集合{1,2,3}分为{1,2}和{3}。此时称有一种方式(即与顺序无关)。
    N=7时,共有四种方式可以将集合{1,2,3,...,7}分为两个部分和相同的子集合:
    {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。
    输入样例
    7
    输出样例
    4


    思路:

    这道题我开始只有一点思路,就是关于这个数加还是不加,想到dfs,但是又想到它无法记得我加了哪个数,无法实现,然后看了别人的博客

    用动态规划,这个真的有点意思。

    dp[i][sum] 中i代表的是i这个数,sum代表的是子集和的整数被限制为sum,然后从加还是不加i这个数进行分类

    1.如果i==0 ,sum==0,这里很关键,就是把0放入这个子集和为0 的集合中,方案数为1;

    2.当i==0,sum>0,无法放入,所以方案数为0;

    3.i>sum,就是说这个数大于这个被限制为数值为sum的子集和,所以无法放入,因此为dp[i-1][sum];

    4.i<=sum,这里需要分类讨论,i这个数有资格放入这个集合中,但是可以放也可以不放,所以为dp[i-1][sum](不放的方案数)+dp[i-1][sum-i](放的方案数),dp[i-1][sum-i]含义:我们要把i这个数放入这个集合中,所以我们要预先就留i这么大的空间,所以我们只有数值为sum-i的子集和


    代码:

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    const int maxn = 2e3+10;
    int dp[50][maxn];
    int main(){
        int n;
        cin>>n;
        int sum;
        sum = (1+n)*n/2;
        if(sum%2==1)
            cout<<"0"<<endl;
        else{
            sum = sum/2;
            dp[0][0] = 1;
            for(int i=1;i<=n;i++)
                dp[0][i] = 0;
            for(int i=1;i<=n;i++){
                for(int j=0;j<=sum;j++){
                    if(j<i)
                        dp[i][j] = dp[i-1][j];
                    else
                        dp[i][j] = dp[i-1][j]+dp[i-1][j-i];
                }
            }
            cout<<dp[n][sum]/2<<endl; 
        }
        return 0;
    }
  • 相关阅读:
    mysql将视图数据迁移到表中
    一、Vant示例文件
    一、VS安装GitHub插件
    二、.net 特性之二
    .net Core jwt策略参数
    一、
    一、.Net Core 3.1 全局序列化
    前端项目
    python 小脚本升级-- 钉钉群聊天机器人
    java 接口测试,使用excel做数据驱动(二)
  • 原文地址:https://www.cnblogs.com/lusiqi/p/11610186.html
Copyright © 2011-2022 走看看