P1466 [USACO2.2]集合 Subset Sums

P1466 [USACO2.2]集合 Subset Sums

这也能动规,而且还是01背包.

 dp[i][j]表示从1~i的数字中选择,能够得到和为j的方案数.那么dp[i][0]=1.对于每个数字选或者不选,有:

dp[i + 1][j] = dp[i][j] + dp[i][j - i],这里的i相当于背包问题中物体i的重量,这里的"重量"就是i自身.

压维,dp[j] += dp[j - i].

此时½∑i=1n即为选取和为两个子集的和的方案数.注意到这里面是有重复部分的,如{1,2,3}被拆分为方案①{1,2},{3}和方案②{3},{1,2}.

输出该方案数除以二即可.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

int n, M;
long long dp[800];

int main(){
    cin >> n;
    M = n * n + n;
    if((M / 2) & 1){
        puts("0");
        return 0;
    }
    M /= 2;         // sum 1 to n

    dp[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = M / 2; j >= i; j--)
            dp[j] += dp[j - i];

    cout << dp[M / 2] / 2;

    return 0;
}
还没完

 怎么看出来这是一道动规题?缩小范围,为什么这是一道背包问题?

因为问题可以转化为取还是不取的问题,如果以搜索的视角看,还有存储结果的需求.

如果说取还是不取,前一段时间做的搜索几乎一直在做这件事情,这两者之间的关系太紧密了.

原文地址:https://www.cnblogs.com/Gaomez/p/14087356.html