LA4794 Sharing Chocolate

 

题意:给出一个长宽确定的矩形,每次可以沿一条直线把它分割成两块长宽都为整数的矩形,问能否通过多次操作得到n块面积分别为a1,a2...an的矩形。

 

与分蛋糕的生日快乐有点像。记忆化搜索、枚举子集。

由于n很小可以直接状压,s表示需要得到的巧克力的状态集合。

因为每次所有的要得到的巧克力面积和等于r*c,可以根据这个剪枝,同时把状态f[r][c][s]变成二维f[r][s]。

然后发现如果写return 1,2;最后会返回2。

//Serene
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn=17,maxs=(1<<15)+10;
int n,r,c,tot[maxs];
int f[110][maxs];

int aa;char cc;
int read() {
	aa=0;cc=getchar();
	while(cc<'0'||cc>'9') cc=getchar();
	while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
	return aa;
}

bool ok(int r,int s) {
	if(f[r][s]) return f[r][s]-1;
	if(s==(s&(-s))) return f[r][s]=2,1;
	int x,y,c=tot[s]/r;
	for(x=(s-1)&s;x;x=(x-1)&s) {
		y=s-x;
		if(tot[x]%c==0&&ok(r*tot[x]/tot[s],x)&&ok(r*tot[y]/tot[s],y)) return f[r][s]=2,1;
		if(tot[x]%r==0&&ok(r,x)&&ok(r,y)) return f[r][s]=2,1;
	}
	return f[r][s]=1,0;
}

int main() {
	n=read();int tt=0;
	while(n) {
		r=read();c=read(); int x;
		memset(tot,0,sizeof(tot));
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;++i) tot[1<<(i-1)]=read();
		for(int i=1;i<(1<<n);++i) {
			x=(i&(-i)); if(i==x) continue;
			tot[i]=tot[x]+tot[i^x];
		}
		printf("Case %d: ",++tt);
		if(r*c!=tot[(1<<n)-1]||!ok(r,(1<<n)-1)) printf("No\n");
		else printf("Yes\n");
		n=read();
	}
	return 0;
}

  

posted @ 2017-09-27 21:33  shixinyi  阅读(224)  评论(0编辑  收藏  举报