记录编号 186406 评测结果 AAAAAAAAAA
题目名称 [UVa 10572] 黑和白 最终得分 100
用户昵称 Gravatarmikumikumi 是否通过 通过
代码语言 C++ 运行时间 0.163 s
提交时间 2015-09-12 17:49:02 内存使用 0.32 MiB
显示代码纯文本
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<map>
#include<cstring>
using namespace std;
typedef long long LL;
int N,M,P[10][10];//0代表无染色,1代表白色,2代表黑色
bool g[10][10]={0};
//状态用一个64位的整数表示,其中,前8个bit表示颜色,后24个表示连通分量的编号,每个连通分量用3个bit
class miku
{
public:
	short comp[10];//每个连通分两的编号
	bool co[10];//每个格子的颜色
	bool L;//左上的格子
	short sum[2];//两种连通分量的个数
	void print()//调试接口
	{
		cout<<"白:"<<sum[0]<<endl;
		cout<<"黑:"<<sum[1]<<endl;
		for(int i=1;i<=N;i++)
			cout<<co[i]<<" ";
		cout<<endl;
		for(int i=1;i<=N;i++)
			cout<<comp[i]<<" ";
		cout<<endl;
		cout<<"L:"<<L<<endl;
	}
	void make()//将每个连通分量重新编号
	{
		int tem[10];
		int tot=0;
		memset(tem,-1,sizeof(tem));
		sum[0]=sum[1]=0;
		for(int i=1;i<=N;i++)
		{
			if(tem[comp[i]]==-1)
			{
				tem[comp[i]]=tot++;
				sum[co[i]]++;
			}
			comp[i]=tem[comp[i]];
		}
	}
	void clear()
	{
		memset(co,0,sizeof(co));
		L=0;
		memset(comp,0,sizeof(comp));
		sum[0]=sum[1]=0;
	}
	LL mul()//状态码
	{
		LL re=0;
		for(int i=1;i<=N;i++)
			re=(re<<1)+co[i];
		for(int i=1;i<=N;i++)
			re=(re<<3)+comp[i];
		return re;
	}
	void change(int a,int b)//把comp为b的全部修改为a
	{
		for(int i=1;i<=N;i++)
			if(comp[i]==b)
				comp[i]=a;
	}
	bool find_comp(int a)
	{
		for(int i=1;i<=N;i++)
			if(comp[i]==a) return 1;
		return 0;
	}
	bool find_co(bool a)
	{
		for(int i=1;i<=N;i++)
			if(co[i]==a) return 1;
		return 0;
	}
};
map<LL,int> f[10][10][2];
int DP(int x,int y,miku &S,int now)//这三个参数分别代表了纵,横,状态,是否需强制染色
{
	if(y==N+1)
	{
		x++;y=1;
	}
	S.make();
	if(x==M+1)
	{
		if(S.sum[0]>1||S.sum[1]>1) return 0;//不满足四连通
		/*S.print();
		for(int i=1;i<=M;i++)
		{
			for(int j=1;j<=N;j++)
				cout<<g[i][j]<<" ";
			cout<<endl;
		}
		cout<<endl;*/
		return 1;
	}
	LL q;
	if(now<0)
	{
		q=S.mul();
		if(f[x][y][S.L].count(q)) 
		{
			/*cout<<x<<" "<<y<<endl;S.print();
			for(int i=1;i<=M;i++)
			{
				for(int j=1;j<=N;j++)
					cout<<g[i][j]<<" ";
				cout<<endl;
			}
			cout<<endl;*/
			return f[x][y][S.L][q];
		}
	}
	miku T;
	int ans=0;
	for(int i=0;i<=1;i++)
	{
		if(x>1&&y>1&&S.L==i&&S.co[y-1]==i&&S.co[y]==i) continue;//四个方块颜色相同
		if(now>=0&&i!=now) continue;
		if(P[x][y]!=0&&P[x][y]-1!=i) continue;
		T=S;
		T.co[y]=i;
		T.L=S.co[y];
		T.comp[y]=T.sum[0]+T.sum[1];
		if(x>1&&T.co[y]==S.co[y]) T.comp[y]=S.comp[y];
		if(y>1&&T.co[y-1]==T.co[y]) T.change(T.comp[y-1],T.comp[y]);
		if(x>1&&T.co[y]!=S.co[y])
		{
			if(!T.find_comp(S.comp[y]))//由于新加的格子,原先的连通块消失
			{
				if(T.find_co(S.co[y])||x<M-1) 
					continue;
				g[x][y]=i;
				ans+=DP(x,y+1,T,i);
				continue;
			}
		}
		g[x][y]=i;
		ans+=DP(x,y+1,T,now);
	}
	if(now<0)
	{
		f[x][y][S.L][S.mul()]=ans;
	}
	return ans;
}
void work()
{
	miku S;
	S.clear();
	int ans=DP(1,1,S,-1);
	printf("%d\n",ans);
}
int main()
{
	freopen("blackandwhite.in","r",stdin);
	freopen("blackandwhite.out","w",stdout);
	scanf("%d%d",&M,&N);
	char s[10];
	for(int i=1;i<=M;i++)
	{
		scanf("%s",s);
		for(int j=1;j<=N;j++)
		{
			if(s[j-1]=='o')
				P[i][j]=1;
			else if(s[j-1]=='#') P[i][j]=2;
			else if(s[j-1]=='.') P[i][j]=0;
			else printf("error\n");
		}
	}
	work();
	return 0;
}