pku3317 Stake Your Claim 极大极小搜索+状压+AB剪枝

感觉我已经快不行惹 感觉自己有点弱竟然写了2h= =

开始并没发现可以状压【英语渣没看懂题目,后来偷窥了一下大神博客,发现空的格子不超过10个,于是我们考虑状压,三进制分别表示空格,0,1,四进制最开始以为开不下= =

然后我们传递还有哪些空格还没被选过,二进制高效处理,新姿势:用pos=log(k+0.5)/log(2.0)或者pos=log(k-0.5)/log(2.0)+1来获取是哪一位

AB剪枝,在搜索某个节点的子树过程中,发现当前子树怎样也无法得到比“当前已搜索过的子树得到的结果”(alpha或者beta)更优的结果时return那个值就行,切记不可把值传给f[now]。

时间复杂度O(n*n*2^m)剪枝或者状压后就可以过惹

Problem: 3317		User: BPM136
Memory: 2768K		Time: 172MS
Language: G++		Result: Accepted

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<bitset>
#define LL long long
#define get(i,j) (i*n+j)
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define down(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 10
#define MIN -10000
#define MAX 10000
struct point
{
	int x,y;
	point()
	{
		x=y=0;
	}
	point(int x_,int y_)
	{
		x=x_;y=y_;
	}
}d[100],ans;
int map[N][N];
int n,nd=0,anss;
int po[21];
int f[1<<20];
char s[100];
bitset<100>v;
int pri[4][2];

int dfs(int x,int y,int k)
{
	if(x<0||y<0||x>=n||y>=n)return 0;
	if(v[get(x,y)])return 0;
	if(map[x][y]!=k)return 0;
	v[get(x,y)]=1;
	int t=1;
	fo(i,0,3)
	t+=dfs(x+pri[i][0],y+pri[i][1],k);
	return t;
}

int getvalue(int now)
{
	v.reset();int st=now;
	fo(i,0,nd-1)
	{
		int t=st%3;st/=3;
		map[d[i].x][d[i].y]=t;
	}
	int ans0=0,ans1=0;
	fo(i,0,n-1)
	{
		fo(j,0,n-1)
		{
//			cout<<get(i,j)<<' '<<i<<' '<<j<<' '<<map[i][j]<<endl;
			if(v[get(i,j)]==0)
			{
//				cout<<1222<<endl;
				int t=dfs(i,j,map[i][j]);
//				cout<<"suess"<<endl;
				if(map[i][j]==1)
				{
					ans0=max(ans0,t);
				}else
				{
					ans1=max(ans1,t);
				}
			}
		}
	}
	fo(i,0,nd-1)
	{
		map[d[i].x][d[i].y]=0;
	}
	return ans0-ans1;
}

int minimax(int status,int dep,int now,int beta);
int maxmini(int status,int dep,int now,int alpha);
int minimax(int status,int dep,int now,int beta)
{
	if(status==0)return getvalue(now);
	if(f[now]!=MIN)return f[now];
	int mi=MAX;
	int st=status;
	while(st)
	{
		int k=st&(-st);
		int pos=log(k+0.5)/log(2.0);
		int t=maxmini(status-k,dep+1,now+po[pos]*2,mi);
		mi=min(mi,t);
		if(mi<=beta)return mi;
		
		st-=k;
	}
	return f[now]=mi;
}

int maxmini(int status,int dep,int now,int alpha)
{
	if(status==0)return getvalue(now);
	if(f[now]!=MIN) return f[now];
	int ma=MIN;
	int st=status;
	while(st)
	{
		int k=st&(-st);
		int pos=log(k+0.5)/log(2.0);
		int t=minimax(status-k,dep+1,now+po[pos],ma);
		ma=max(ma,t);
		if(ma>=alpha)return ma;
		
		if(status==(1<<nd)-1)
		{
			if(ma>anss)
			{
				ans=d[pos];
				anss=ma;
			}
		}
		st-=k;
	}
	return f[now]=ma;
}

void init()
{
	int c1=0,c0=0;nd=0;
	memset(map,0,sizeof(map));
	fo(i,0,n-1)
	{
		scanf("%s",s);
		fo(j,0,n-1)
		{
			if(s[j]=='.')
			{
				map[i][j]=0;
				d[nd++]=point(i,j);
			}else
			if(s[j]=='0')
			{
				map[i][j]=1,c0++;
			}else
			if(s[j]=='1')
			{
				map[i][j]=2,c1++;
			}
		}
	}
	if(c0>c1)
	{
		fo(i,0,n-1)
		{
			fo(j,0,n-1)
			if(map[i][j])
			{
				map[i][j]^=3;
			}
		}
	}
	fo(i,0,1<<20-1)f[i]=MIN;
    ans=point(0,0);anss=MIN;
}

void check()
{
	fo(i,0,n-1)
	{
		fo(j,0,n-1)
		cout<<map[i][j];
		cout<<endl;
	}cout<<endl;
}

int main()
{
	int tt=0;
	fo(i,-1,1)
	fo(j,-1,1)
	if(abs(i-j)==1)
	{
		pri[tt][0]=i,pri[tt++][1]=j;
	}
	po[0]=1;nd=0;
	fo(i,1,10)po[i]=po[i-1]*3;
	while(scanf("%d",&n)!=EOF&&n)
	{
		init();
//		check();
		maxmini((1<<nd)-1,0,0,MAX);
		printf("(%d,%d) %d\n",ans.x,ans.y,anss);
		fo(i,0,nd-1)d[i]=point(0,0);nd=0;
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值