pku1568 Find the Winning Move 完全极大极小搜索

 比较简单,因为只有三种局面也没有权重不知道怎么AB剪枝= =我们可以直接用1表示正无穷,-1表示负无穷,0表示和局

有一个强力剪枝那就是,如果当前只下了<=4颗棋子那就一定无解

然而比赛的时候这个剪枝不是特别敢加.

不过实际上那个剪枝可能只是数学证明,实际测试改成7都是可以AC的

时间复杂度(2^m)*16,可秒过,然而让人遗憾的是我并没有0ms出现= =

Problem: 1568		User: BPM136
Memory: 688K		Time: 16MS
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 4
#define MIN -2
int map[N][N];
int n=4,m=(1<<16)-1,cnt,cstatus;
char s;

void init()
{
	memset(map,0,sizeof(map));
	cnt=0;cstatus=0;int po=1;
	fo(i,0,n-1)
	{
		fo(j,0,n-1)
		{
			scanf("%c",&s);
			if(s=='.')
			{
				map[i][j]=0;
			}else
			if(s=='o')
			{
				map[i][j]=2;
				cnt++;
			}else
			if(s=='x')
			{
				map[i][j]=1;
				cnt++;
			}
			if(!map[i][j])cstatus+=po;
			po<<=1;
		}
		getchar();
	}
}

bool getvalue(int x,int y)
{
	if(x==y)
	{
		if(map[0][0]==map[1][1])
		if(map[1][1]==map[2][2])
		if(map[2][2]==map[3][3])
		return 1;
	}
	if(x==3-y)
	{
		if(map[0][3]==map[1][2])
		if(map[1][2]==map[2][1])
		if(map[2][1]==map[3][0])
		return 1;
	}
	int tot=0;
	fo(i,0,3)if(map[x][i]==map[x][y])tot++;
	if(tot==4)return 1;
	tot=0;
	fo(i,0,3)if(map[i][y]==map[x][y])tot++;
	if(tot==4)return 1;
	return 0;
}

int maxmini(int status,int i,int j);
int minimax(int status,int i,int j);
int maxmini(int status,int i,int j)
{
	if(getvalue(i,j))return -1;
	if(cnt==16)return 0;
	int st=status,ma=-2;
	while(st)
	{
		int k=st&(-st);
		int pos=log(k+0.5)/log(2.0);
		int x=pos/4,y=pos%4;
		map[x][y]=1;cnt++;
		int t=minimax(status-k,x,y);
		map[x][y]=0;cnt--;
		ma=max(ma,t);
		if(ma==1)return 1;
		st-=k;
	}
	return ma;
}

int minimax(int status,int i,int j)
{
	if(getvalue(i,j))return 1;
	if(cnt==16)return 0;
	int st=status,mi=2;
	while(st)
	{
		int k=st&(-st);
		int pos=log(k+0.5)/log(2.0);
		int x=pos/4,y=pos%4;
		map[x][y]=2;cnt++;
		int t=maxmini(status-k,x,y);
		map[x][y]=0;cnt--;
		mi=min(mi,t);
		if(mi==-1)return -1;
		st-=k;
	}
	return mi;
}

void work()
{
	int st=cstatus;
	while(st)
	{
		int k=st&(-st);
		int pos=log(k+0.5)/log(2.0);
		int x=pos/4,y=pos%4;
		map[x][y]=1;cnt++;
		int t=minimax(cstatus-k,x,y);
//		cout<<k<<' '<<pos<<' '<<x<<' '<<y<<' '<<t<<endl;
		if(t==1)
		{
			printf("(%d,%d)\n",x,y);
			return;
		}
		map[x][y]=0;cnt--;
		st-=k;
	}
	printf("#####\n");
}

int main()
{
	char ch;
	while(scanf("%c",&ch))
	{
		if(ch=='$')break;  
                scanf("%c",&ch);
		init();
		if(cnt<=7)
		{
			printf("#####\n");
			continue;
		}
		work();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值