CodeForces - 687C The Values You Can Make (多背包解法)

题目链接: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\n",cnt );
    for (int i=1; i<=cnt; i++)
        printf("%d%c",ans[i],i==cnt?'\n':' ');
    return 0;
}

 

posted @ 2020-07-08 00:04  lonely_wind  阅读(259)  评论(0编辑  收藏  举报