有了之前的基础,3进制DP根本不在话下啊,半个小时就搞定了(本来就是水题好不好)
极大极小过程+记忆化搜索
话说第一次接触博弈论,还有点紧张(紧张个P啊连Alpha-Beta剪枝都没有的水题)
然后大概看了下极大极小过程,发现这题根本用不到什么啊TAT
顺便吐槽数据好水63MS就过了,竟然rank27,不科学。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1024*1024+5;
const int inf=1e9;
char mp[10][10];
int f[N],x[12],y[12],bin[30],tot,n;
bool vis[N],tra[10][10];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int get(int s,int pos){
if(s&bin[pos<<1])return 1;
if(s&bin[pos*2-1])return 2;
return 0;
}
int put(int x,int pos){
switch(x){
case 0:return 0;
case 1:return bin[pos<<1];
case 2:return bin[2*pos-1];
}
}
void print(int s){
for(int i=1;i<=tot;i++)
printf("%d",get(s,i)-1);putchar('\n');
}
int dfs(int x,int y){
if(tra[x][y])return 0;
int ans=1;tra[x][y]=1;
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx<1||tx>n||ty<1||ty>n||tra[tx][ty]||mp[tx][ty]!=mp[x][y])continue;
ans+=dfs(tx,ty);
}
return ans;
}
int calc(int s){
for(int i=1;i<=tot;i++){
int t=get(s,i);
if(t==1)mp[x[i]][y[i]]='0';
else mp[x[i]][y[i]]='1';
}
memset(tra,0,sizeof(tra));
int sum0=0,sum1=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(mp[i][j]=='0')sum0=max(sum0,dfs(i,j));
else sum1=max(sum1,dfs(i,j));
return sum0-sum1;
}
int dfs(int s,int p,int step){
if(vis[s])return f[s];
vis[s]=true;
if(!step)return f[s]=calc(s);
f[s]=p?inf:-inf;
for(int i=1;i<=tot;i++)
if(!get(s,i)){
if(p)f[s]=min(f[s],dfs(s|put(p+1,i),p^1,step-1));
else f[s]=max(f[s],dfs(s|put(p+1,i),p^1,step-1));
}
return f[s];
}
int main(){
//freopen("a.in","r",stdin);
bin[1]=1;
for(int i=2;i<=24;i++)bin[i]=bin[i-1]<<1;
while(scanf("%d",&n)&&n){
tot=0;int sum=0;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=n;j++)
if(mp[i][j]=='.')x[++tot]=i,y[tot]=j;
else sum++;
}
memset(vis,0,sizeof(vis));
int ans=dfs(0,sum&1,tot);
for(int i=1;i<=tot;i++)
if(f[put((sum&1)+1,i)]==ans){
if(sum&1)ans*=-1;
printf("(%d,%d) %d\n",x[i]-1,y[i]-1,ans);
break;
}
}
return 0;
}