记录编号 |
186406 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[UVa 10572] 黑和白 |
最终得分 |
100 |
用户昵称 |
mikumikumi |
是否通过 |
通过 |
代码语言 |
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;
}