记录编号 421921 评测结果 AAAAAAAAAA
题目名称 [UVa 10572] 黑和白 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 0.280 s
提交时间 2017-07-08 14:52:22 内存使用 0.31 MiB
显示代码纯文本
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
int n,m;
char str[11][11];
struct state{
	int fa[11],size[11],S;
	int ok_black,ok_white;
	//fa为最小表示,S表示这些位的颜色,1为黑色
	state(ll x=0){
		memset(fa,0,sizeof fa);
		memset(size,0,sizeof size);
		ok_black=x>>50&1;
		ok_white=x>>60&1;
		for (int i=0;i<m;i++) fa[i]=x&7,x>>=3;
		for (int i=0;i<m;i++) size[fa[i]]++;
		S=x&((1<<(m+1))-1);
	}
	int get(int p){return S>>p&1;}
	bool white(int i,int j){//检查这个格子涂白色是否合法
		if (!ok_white) return 0;//白格子已经不联通了
		if (i&&j&&!get(j-1)&&!get(j)&&!get(j+1)) return 0;//形成了2*2全白网格
		if (i&&get(j+1)&&size[fa[j]]==1){
			if (ok_black) ok_black=0;//上面的黑格子不联通
				else return 0;
		}
		if (i&&get(j+1)){//若上面是黑格子,重构这个联通块
			int last,set=fa[j];
			for (int i=0;i<m;i++)
				if (i!=j&&fa[i]==set){last=i;break;}
			for (int i=0;i<m;i++)
				if (i!=j&&fa[i]==set) fa[i]=last;
		}
		int set=j;
		if (j&&!get(j-1)) set=min(set,fa[j-1]);//左边是白格子
		if (i&&!get(j+1)) set=min(set,fa[j]);//上面是白格子
		if (j&&!get(j-1)){//合并左边的联通块
			int s=fa[j-1];
			for (int i=0;i<m;i++)
				if (fa[i]==s) fa[i]=set;
		}
		if (i&&!get(j+1)){//合并上边的联通块
			int s=fa[j];
			for (int i=0;i<m;i++)
				if (fa[i]==s) fa[i]=set;
		}
		fa[j]=set;
		S&=~(1<<j);//将这一位颜色染白
		return 1;
	}
	bool black(int i,int j){
		if (!ok_black) return 0;//黑格子已经不联通了
		if (i&&j&&get(j-1)&&get(j)&&get(j+1)) return 0;//形成了2*2全黑网格
		if (i&&!get(j+1)&&size[fa[j]]==1){
			if (ok_white) ok_white=0;
				else return 0;//上面的白格子不联通
		}
		if (i&&!get(j+1)){//若上面是白格子,重构这个联通块
			int last,set=fa[j];
			for (int i=0;i<m;i++)
				if (i!=j&&fa[i]==set){last=i;break;}
			for (int i=0;i<m;i++)
				if (i!=j&&fa[i]==set) fa[i]=last;
		}
		int set=j;
		if (j&&get(j-1)) set=min(set,fa[j-1]);//左边是黑格子
		if (i&&get(j+1)) set=min(set,fa[j]);//上面是黑格子
		if (j&&get(j-1)){//合并左边的联通块
			int s=fa[j-1];
			for (int i=0;i<m;i++)
				if (fa[i]==s) fa[i]=set;
		}
		if (i&&get(j+1)){//合并上边的联通块
			int s=fa[j];
			for (int i=0;i<m;i++)
				if (fa[i]==s) fa[i]=set;
		}
		fa[j]=set;
		S|=(1<<j);//将这一位颜色染黑
		return 1;
	}
	bool ok(){
		int block=0;
		for (int i=0;i<m;i++)
			if (fa[i]==i) block++;
		if (block>2) return 0;
		int is_black=0,is_white=0;
		for (int i=1;i<=m;i++)
			if (get(i)) is_black=1;
				else is_white=1;
		if (is_black&&!ok_black) return 0;
		if (is_white&&!ok_white) return 0;
		return 1;
	}
	ll val(){
		ll x=S;
		for (int i=m-1;i>=0;i--) x=x<<3|fa[i];
		x|=((ll)ok_black<<50);
		x|=((ll)ok_white<<60);
		return x;
	}
	void print(){
		puts("this is fa array:");
		for (int i=0;i<m;i++) printf("%d ",fa[i]);
		puts("");
		puts("this is the color set");
		for (int i=0;i<=m;i++) printf("%d",S>>i&1);
		puts("");
		printf("black:%d\n",ok_black);
		printf("white:%d\n",ok_white);
		puts("state end.");
		puts("");
	}
};
typedef pair<ll,ll> pr;
struct dp_array{
	vector<pr> v;//first为状态,second为出现次数
	map<ll,ll> M;
	void clear(){
		v.clear();
		M.clear();
	}
	void add(ll S,ll d){//状态S的出现次数+d
		if (!M.count(S)) M[S]=v.size(),v.push_back(pr(S,d));
			else v[M[S]].second+=d;
	}
}*x=new dp_array(),*y=new dp_array();
void solve(int i,int j){
	y->clear();
	for (int k=0;k<x->v.size();k++){
		state S(x->v[k].first),T;
		ll v=x->v[k].second;
		if (str[i][j]!='#'){
			T=S;
			if (T.white(i,j)) y->add(T.val(),v);
		}
		if (str[i][j]!='o'){
			T=S;
			if (T.black(i,j)) y->add(T.val(),v);
		}
	}
	swap(x,y);
}
void next_line(int i){
	y->clear();
	for (int k=0;k<x->v.size();k++){
		state S(x->v[k].first);
		S.S&=~(1<<m);
		S.S<<=1;
		y->add(S.val(),x->v[k].second);
	}
	swap(x,y);
}
int main()
{
	freopen("blackandwhite.in","r",stdin);
	freopen("blackandwhite.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=0;i<n;i++) scanf("%s",str[i]);
	x->add((1ll<<50)|(1ll<<60),1);
	for (int i=0;i<n;next_line(i),i++)
		for (int j=0;j<m;solve(i,j),j++);
	ll ans=0;
	for (int i=0;i<x->v.size();i++){
		state S(x->v[i].first);
		if (S.ok()) ans+=x->v[i].second;
	}
	printf("%lld\n",ans);
	return 0;
}