题意:有一块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; }