UVA 1099【状态压缩】

题意:有一块x*y的巧克力,问你是否可以分成n块大小分别为aI的小巧克力

分析:n<=15,很小,可以用二进制记录每种组合情况,定义dp[s][x]表示s集合的巧克力能否组成边长为x的大巧克力。

然后枚举s的子集,判断子集能否构成。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 1<<15
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int a[20];
int sum[Mn];
int dp[Mn][105];
int lowbit(int x) {
    return x&(-x);
}
int countbit(int x) {
    int re=0;
    while(x) {
        re++;
        x-=lowbit(x);
    }
    return re;
}
int dfs(int s,int x) {
    if(dp[s][x]!=-1) return dp[s][x];
    if(countbit(s)==1) return dp[s][x]=1;
    int y=sum[s]/x;
    dp[s][x]=0;
    for(int s0=(s-1)&s;s0;s0=(s0-1)&s) {
        int s1=s^s0;
        if(sum[s0]%x==0&&dfs(s0,min(x,sum[s0]/x))&&dfs(s1,min(x,sum[s1]/x)))
            return dp[s][x]=1;
        if(sum[s0]%y==0&&dfs(s0,min(y,sum[s0]/y))&&dfs(s1,min(y,sum[s1]/y)))
            return dp[s][x]=1;
    }
    return dp[s][x]=0;
}
int main() {
    int n,x,y,cas=0;
    while(scanf("%d",&n)) {
        if(n==0) break;
        cas++;CLR(sum,0);
        scanf("%d%d",&x,&y);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        for(int s=1;s<(1<<n);s++)
            for(int i=0;i<n;i++)
                if(s&(1<<i)) sum[s]+=a[i];
        int flag=1;
        int all=(1<<n)-1;CLR(dp,-1);
        if(sum[all]!=x*y||sum[all]%x) flag=0;
        else if(!dfs(all,min(x,y))) flag=0;
        printf("Case %d: ",cas);
        if(flag) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


你可能感兴趣的:(UVA 1099【状态压缩】)