CCF 201803-4 棋局评估--深度(对抗)搜索

思路:

这道题逻辑必须非常清晰才能做出来。首先要明白这是一个博弈论的问题,也就是说,你的对手希望他得高分,你希望你得高分,可是你分数高了他的分就低了,所以是一种博弈。
下棋的时候,你希望走出最好的局面,即使输也要分数最高,而你的对手恰恰相反,他要走出他的最好局面,也就是你的最坏局面,让你分数最低。
这样交替行棋,也就完成了对棋局的推演,得出高手的最终局势。
这本质上是博弈论中的对抗搜索,有不懂的地方可以自行百度。

#include<bits/stdc++.h>
using namespace std;

int chess[3][3];

int canwin(){                         //判断局势
	int victory=0;
	int temp;
	for(temp=1;temp<3;temp++){
		int flag;
		//纵横是否成棋 
		for(int i=0;i<3;i++){
			flag=1;
			for(int j=0;j<3;j++){
				if(chess[i][j]!=temp){
					flag=0;
					break;
				}
			}
			if(flag==1){
				victory=1;
				break;
			}
			flag=1;
			for(int j=0;j<3;j++){
				if(chess[j][i]!=temp){
					flag=0;
					break;
				}
			}
			if(flag==1){
				victory=1;
				break;
			}
		}
		if(flag==1){
			victory=1;
			break;
		}
		//对角线是否成棋 
		flag=1;
		for(int i=0;i<3;i++){
			if(chess[i][i]!=temp){
				flag=0;
				break;
			}
		}
		if(flag==1){
			victory=1;
			break;
		}
			
		flag=1;
		for(int i=0;i<3;i++){
			if(chess[i][2-i]!=temp){
				flag=0;
				break;
			}
		}
		if(flag==1){
			victory=1;
			break;
		}
	}
	if(victory==1)return temp;
	else return -1;
}

int zeronum(){                        //统计空位个数 
	int num=0;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			if(chess[i][j]==0)num++;
		}
	}
	return num;
}

int score(){                          //分数计算 
	int win=canwin(),ans=zeronum()+1;
	switch(win){
		case -1:
			return 0;
			break;
		case 1:
			return ans;
			break;
		case 2:
			return -ans;
			break;
	}
}
int dfs(int stone){                       //深度(对抗)搜索     
	if(!zeronum())return 0;               //棋盘已满 和棋 
	
	int maxs=-100,mins=100;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			if(!chess[i][j]){             //寻找落子位置 
				chess[i][j]=stone;        //落子有悔 
				int ans=score();          //判断是否获胜 并得出相应分数 
				if(ans){                  //若获胜 
					chess[i][j]=0;        //悔棋 
					return ans;           //返回分数 
				}
				if(stone==1) maxs=max(maxs,dfs(2));//Bob行棋 返回最小的分数 也即对Bob最有利的分数
				else         mins=min(mins,dfs(1));//Alice行棋 返回最大的分数 也即对Alice最有利的分数
				chess[i][j]=0;            //悔棋 
			}
		}
	}
	return stone==1? maxs:mins;           //0-Alice-Max,1-Bob-Min 
}

int main(){
	int T;
	cin>>T;
	while(T--){
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				chess[i][j]=0;
			}
		}
		//输入 
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				cin>>chess[i][j];
			}
		}
		//处理
		int t=score();           
		if(t){                    //判断是否为定势 
			cout<<t<<endl;
			continue;
		}
		
		t=dfs(1);                 //Alice行棋 
		//输出
		cout<<t<<endl;            //输出 
	}
}

样例:
/*
样例输入
3
1 2 1
2 1 2
0 0 0
2 1 1
0 2 1
0 0 2
0 0 0
0 0 0
0 0 0

5
1 1 1
2 1 2
0 0 0
2 1 1
0 2 1
0 0 2
2 2 2
1 2 1
2 0 1
2 1 1
0 2 1
2 1 1
0 0 0
0 0 0
0 0 0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值