Sharing Chocolate LA 4794 状压dp

LA 4794

题意很简单,给你一块长x宽y的大巧克力,再给你n个面积为ai的小巧克力,问你能不能再若干次切割把大巧克力切割成n个巧克力,一次切割,必须把一块巧克力变成两块,不能切弯的,能就输出Yes,不能输出No

因为n的大小为16,所以可以用二进制表示当前剩下的巧克力集合,如果剩下巧克力集合的子集模当前的x或者y为0,可以进行下一步递推,直到只剩下一块巧克力或者不能不能操作为止,可用记忆化搜索。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=16;
const int maxw=110;
int d[1<<maxn][maxw],vis[1<<maxn][maxw];
int A[maxw],sum[1<<maxn];
int bitcount(int x)
{
	return x==0?0:bitcount(x/2)+(x&1);//之前写+x&1,wa的我精神奔溃,位运算优先级低!! 
}
int dp(int s,int x)
{
	if(vis[s][x])
	return d[s][x];
	vis[s][x]=1;
	int& ans=d[s][x];
	if(bitcount(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 Kase=0;
	int n,x,y,i,j;
	while(~scanf("%d",&n)&&n)
	{
		int ans=0;
		scanf("%d%d",&x,&y);
		for(i=0;i<n;i++)
		scanf("%d",&A[i]);
		for(i=0;i<(1<<n);i++)
		{
			sum[i]=0;
			for(j=0;j<n;j++)
			if(i&(1<<j))
			sum[i]+=A[j];
		}
		memset(vis,0,sizeof(vis));
		int ALL=(1<<n)-1;
		if(sum[ALL]==x*y)//如果大巧克力面积不等于所有小巧克力面积之和,肯定是No 
		ans=dp(ALL,min(x,y));
		printf("Case %d: %s\n",++Kase,ans?"Yes":"No");
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80086318
LA