第五届华中区程序设计邀请赛暨武汉大学第十四届校赛 Problem 1608 - Calculation




链接:戳这里


Problem 1608 - Calculation
Time Limit: 500MS   Memory Limit: 65536KB   
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 S, by + 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个数ai(1<=i<=n),任意去组合这些数,分成k个集合,集合里面的ai可以做+-操作,问你最多可以组成多少个集合使得集合的sum=m


思路:第一次写状压,大概就是把这n个数弄成2进制,每个数取或不取分别代表二进制上是1或者0,然后一开始先给每个集合加数进去,对应的二进制上第i位为1的就加上a[i]

然后要处理+-操作的问题,因为一开始我们是加上a[i]这个数啊,所以如果这个数是减的话我们直接减去两倍的a[i]就是了

对于当前的集合S,对于它的子集S0  减去两倍可以等于m的话说明这个集合S是满足操作和为m的  标记这个集合为1

接下来还是枚举集合S的子集S0,如果当前的集合S0是可以使得和为m的话,则dp[S]的权值为对应的S-S0这个子集的权值+1   即dp[S]=max(dp[S],dp[S-S0]+1)

然后直接输出dp[(1<<n)-1]这个总集合内满足条件的个数


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int T,n;
ll m,a[55],s[32768];
int f[32768],dp[32768];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%lld",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        for(int S=0;S<(1<<n);S++){
            s[S]=0;
            for(int i=0;i<n;i++){
                if(S & (1<<i) ) s[S]+=a[i];
            }
        }
        for(int S=1;S<(1<<n);S++){
            f[S]=0;
            for(int S0=S;S0;S0=S&(S0-1)){
                ll t=s[S]-2*s[S0];
                if(t==m || s[S]==m) {
                    f[S]=1;
                    break;
                }
            }
        }
        int ans=0;
        for(int S=1;S<(1<<n);S++){
            dp[S]=0;
            for(int S0=S;S0;S0=S&(S0-1)){
                if(f[S0]==1) dp[S]=max(dp[S],dp[S^S0]+1);
            }
        }
        cout<<dp[(1<<n)-1]<<endl;
    }
    return 0;
}


你可能感兴趣的:(第五届华中区程序设计邀请赛暨武汉大学第十四届校赛 Problem 1608 - Calculation)