• CodeForces


    题目链接:https://codeforces.com/problemset/problem/687/C

    题目大意:给你n个数,然后让这些数相加组合,然后在这些组合的数里可以再相加组合搞出给定 k,输出这些组合的数。

    Examples

    Input
    6 18
    5 6 1 10 12 2
    Output
    16
    0 1 2 3 5 6 7 8 10 11 12 13 15 16 17 18
    Input
    3 50
    25 25 50
    Output
    3
    0 25 50

    emmm,实际上我们可以看到的是这些数是成对出现的,那么我们只需要对每对数进行搜寻判断就好了,如果$i,k-i$可以同时由上面的数组合而成,那么我们就可以肯定$i,k-i$是存在的,可以输出的。那么怎么判断一对数能否同时由上面的数组合而成呢?应该很容易想到背包,之前讲过的多背包问题也就在这里再一次的运用上了,定义背包状态$dp[i][j]$表示$i,j$容量的时候最大能够取得的价值,那么如果$dp[i][k-i]==k$也就是两个背包刚好都装满了。于是。。。。此题结束。。。

    以下是AC代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int mac=550;
    
    int a[mac],ans[mac];
    int dp[mac][mac];
    
    int main()
    {
        int n,m;
        scanf ("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
            scanf ("%d",&a[i]);
        for (int i=1; i<=n; i++)
            for (int j=m; j>=0; j--)
                for (int k=m; k>=0; k--){
                    if (j-a[i]>=0) dp[j][k]=max(dp[j][k],dp[j-a[i]][k]+a[i]);
                    if (k-a[i]>=0) dp[j][k]=max(dp[j][k],dp[j][k-a[i]]+a[i]);
                }
        int cnt=0;
        for (int i=0; i<=(m-1)/2; i++){
            if (dp[i][m-i]==m) ans[++cnt]=i,ans[++cnt]=m-i;
        }
        if (!(m&1) && dp[m/2][m/2]==m) ans[++cnt]=m/2;  
        sort(ans+1,ans+1+cnt);
        printf("%d
    ",cnt );
        for (int i=1; i<=cnt; i++)
            printf("%d%c",ans[i],i==cnt?'
    ':' ');
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    系统进程
    Javascript中的常用事件
    进程信息库网址
    C#中使用临时存储过程
    Transactsql 中的 rollup 和cube的使用
    如何使用fckeditor在线编辑器(asp)
    微软将 jQuery IntelliSense整合到Visual Studio
    no such file to load openssl Anny
    Ubuntu 防火墙 ufw Anny
    Install Apache 2 from Source on Linux(转) Anny
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13264361.html
Copyright © 2020-2023  润新知