第五届华中区程序设计邀请赛暨武汉大学第十四届校赛 网络预选赛 E Calculation 状态压缩DP枚举子集

Problem 1608 - Calculation
 
Description
Today, Alice got her math homework again!
She had n integers, and she needed to divide them into several piles or one pile. For each pile, if the teacher could get Sby + or – operator, then Alice got 1 small red flower. Alice wanted to get as many flowers as possible. Could you help her? Just tell her the maximum number of flowers she could get.
Input
The input consists of several test cases.
The first line consists of one integer T (T <= 100), meaning the number of test cases.
The first line of each test cases consists of two integer n (n<=14), meaning the number of the integer, and S (0<= S<= 100000000), meaning the result which teacher wanted.
The next line consists of n integer a1, a2, …, an (0<= ai <= 10000000).
You should know a few cases that n is larger than 12.
Output
For each test case, output one line with one integer without any space.
Sample Input
2
5 5
1 2 3 4 5
5 5
1 2 3 8 8
Sample Output
3
2
 
题意:
 
   给你n个数和S,
   让你把这N个数分成任意个集合块,集合块内可以通过任意加减 得到一个值,假如这个值等于S,则答案加一,问最大是多少
 
题解:
    
   N的范围是小于14
  容易想到状态压缩,
  我们就预处理出 每个子集 取的数的和 也就是全取正
  再通过不断取负号 为什么不用 不取的情况,因为子集会包含在内
  最后dp统计答案就好无聊
 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int N = 1e5+10, M = 50, mod = 1e9+9, inf = 1e9+9;
typedef long long ll;


int dp[1<<15],n,m,a[N],b[N ],c[N];
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(int i=0;i<(1<<n);i++) {
                b[i] = 0;dp[i] = 0;c[i] = 0;
            for(int j=0;j<n;j++) {
                if(i&(1<<j)) b[i]+=a[j];
            }
        }
        for(int i=0;i<(1<<n);i++) {
            if(b[i]==m) c[i]=1;
            for(int j=i;j;j = (j-1)&i) {
                if(c[j]) {c[i] = 1;break;}
              if(b[i]-b[j]-b[j]==m) {c[i] =1;break;}
            }
        }
        for(int i=0;i<(1<<n);i++) {
            dp[i] = 0;
            for(int j=i;j;j = (j-1)&i) {
                if(c[j]) dp[i] = max(dp[i], dp[i^j] + 1);
            }
        }
        printf("%d
",dp[(1<<n)-1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zxhl/p/5372337.html