题目大意:

思路:这里分的时候是把集合分成两个,并且把这个矩阵块分成两个。分别等于这两个集合的矩阵和,当一个集合只有一个元素,那么就满足条件了。

#include <bits/stdc++.h>
#define LL long long
using namespace std;

int a[20];
int d[1<<20][150], sum[1<<20], vis[1<<20][150];

int ok(int s){
    return s==0?0:ok(s/2)+s%2;
}

int dp(int s, int x){

    if(vis[s][x]){
        return d[s][x];
    }
    int &ans=d[s][x];
    vis[s][x]=1;

    if(ok(s)==1){//如果这个集合只有一个需要满足的块,满足条件
        return ans=1;
    }

    int y=sum[s]/x;
    for(int s0=(s-1)&s; s0; s0=(s0-1)&s){
            
        int s1=s-s0;//分成两个的集合
    
        //横切, 一块蛋糕分配一个集合
        if(sum[s0]%x==0&&dp(s0, min(x, sum[s0]/x))&&dp(s1, min(x, sum[s1]/x))){
            return ans=1;
        }
        //竖切, 一块蛋糕分配一个集合
        if(sum[s0]%y==0&&dp(s0, min(y, sum[s0]/y))&&dp(s1, min(y, sum[s1]/y))){
            return ans=1;
        }
    }
    return ans=0;
}

int main()
{
    int T=1, n, x, y;
    while(scanf("%d", &n)==1&&n){

        scanf("%d%d", &x, &y);

        for(int i=0; i<n; i++){
            scanf("%d", &a[i]);
        }

        memset(sum, 0, sizeof(sum));

        for(int s=0; s<(1<<n); s++){
            for(int i=0; i<n; i++){
                if(s&(1<<i)){
                    sum[s]+=a[i];
                }
            }
        }

        memset(d, 0, sizeof(d));
        memset(vis, 0, sizeof(vis));
        int ALL=(1<<n)-1;
        int ans;
        if(sum[ALL]!=x*y||sum[ALL]%x!=0){//必须满足倍数关系才可能满足
            ans=0;
        }
        else{
            ans=dp(ALL, min(x, y));
        }
        printf("Case %d: %s\n", T++, ans?"Yes":"No");
    }

    return 0;
}