题目:给出一个n*n包含0或1或.的矩阵,两个依次找一个空格子,放入0和1,最终看连通0多还是连通的1多,得分是一个选手的最大连通数减去另一个选手的。问当前局面的操作者能够得的最大的分数,及最大分数下最小字典序的操作。
思路:有的说alpha-beta剪枝和记忆化搜索不能一起使用,有的说只要把参数记下来就可以一起用
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<list>
#include<numeric>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define INF 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define PP puts("*********************");
template<class T> T f_abs(T a){ return a > 0 ? a : -a; }
template<class T> T gcd(T a, T b){ return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
// 0x3f3f3f3f3f3f3f3f
//0x3f3f3f3f
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
struct Node{
int x,y;
Node(int _x=0,int _y=0):x(_x),y(_y){}
}p[15],ansp;
int n,tot,best;
char str[10][10];
int vis[10][10],num;
int p3[15],dp[60000];
bool judge(int x1,int y1,int x2,int y2){
if(x2>=0&&x2<n&&y2>=0&&y2<n&&str[x1][y1]==str[x2][y2]&&!vis[x2][y2])
return true;
return false;
}
void dfs(int x,int y){
if(vis[x][y]) return;
vis[x][y]=1;
num++;
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(judge(x,y,nx,ny))
dfs(nx,ny);
}
}
int get_score(){
mm(vis,0);
int c1=0,c2=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(vis[i][j]) continue;
num=0;
dfs(i,j);
if(str[i][j]=='0') c1=max(c1,num);
else c2=max(c2,num);
}
return c1-c2;
}
int MaxSearch(int status,int dep,int now,int alpha);
int MinSearch(int status,int dep,int now,int beta);
int MinSearch(int status,int dep,int now,int beta){
if(status==0) return get_score();
if(dp[now]!=-INF) return dp[now];
int ans=INF,remain=status;
while(remain){
int seg=remain&(-remain);
int k=0;
for(k=0;;k++)
if((1<<k)&seg)
break;
str[p[k].x][p[k].y]='1';
int tmp=MaxSearch(status-seg,dep+1,now+2*p3[k],ans);
str[p[k].x][p[k].y]='.';
if(ans>tmp) ans=tmp;
if(ans<=beta) return ans;
remain-=seg;
}
return dp[now]=ans;
}
int MaxSearch(int status,int dep,int now,int alpha){
if(status==0) return get_score();
if(dp[now]!=-INF) return dp[now];
int ans=-INF,remain=status;
while(remain){
int seg=remain&(-remain);
int k=0;
for(k=0;;k++)
if((1<<k)&seg)
break;
str[p[k].x][p[k].y]='0';
int tmp=MinSearch(status-seg,dep+1,now+p3[k],ans);
str[p[k].x][p[k].y]='.';
if(ans<tmp) ans=tmp;
if(ans>=alpha) return ans;
if(dep==0){
if(ans>best||(ans==best&&(p[k].x<ansp.x||(p[k].x==ansp.x&&p[k].y<ansp.y)))){
best=ans;
ansp=p[k];
}
}
remain-=seg;
}
return dp[now]=ans;
}
int main(){
// freopen("D:\\input.txt","r",stdin);
// freopen("D:\\output.txt","w",stdout);
p3[0]=1;
for(int i=1;i<=10;i++) p3[i]=3*p3[i-1];
while(~scanf("%d",&n)){
if(!n) break;
int c1=0,c2=0;
tot=0;
for(int i=0;i<n;i++)
scanf("%s",str[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
if(str[i][j]=='.') p[tot++]=Node(i,j);
else if(str[i][j]=='0') c1++;
else c2++;
}
if(c1>c2){//把'0'搞成先手
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(str[i][j]=='0') str[i][j]='1';
else if(str[i][j]=='1') str[i][j]='0';
}
best=-INF;
for(int i=0;i<=p3[tot];i++) dp[i]=-INF;
MaxSearch((1<<tot)-1,0,0,INF);
printf("(%d,%d) %d\n",ansp.x,ansp.y,best);
}
return 0;
}