CCF 棋盘评估 100分

试题编号:201803-4
试题名称:棋局评估
时间限制:1.0s
内存限制:256.0MB
问题描述:

问题描述

  Alice和Bob正在玩井字棋游戏。
  井字棋游戏的规则很简单:两人轮流往3*3的棋盘中放棋子,Alice放的是“X”,Bob放的是“O”,Alice执先。当同一种棋子占据一行、一列或一条对角线的三个格子时,游戏结束,该种棋子的持有者获胜。当棋盘被填满的时候,游戏结束,双方平手。
  Alice设计了一种对棋局评分的方法:
  - 对于Alice已经获胜的局面,评估得分为(棋盘上的空格子数+1);
  - 对于Bob已经获胜的局面,评估得分为 -(棋盘上的空格子数+1);
  - 对于平局的局面,评估得分为0;


  例如上图中的局面,Alice已经获胜,同时棋盘上有2个空格,所以局面得分为2+1=3。
  由于Alice并不喜欢计算,所以他请教擅长编程的你,如果两人都以最优策略行棋,那么当前局面的最终得分会是多少?

输入格式

  输入的第一行包含一个正整数T,表示数据的组数。
  每组数据输入有3行,每行有3个整数,用空格分隔,分别表示棋盘每个格子的状态。0表示格子为空,1表示格子中为“X”,2表示格子中为“O”。保证不会出现其他状态。
  保证输入的局面合法。(即保证输入的局面可以通过行棋到达,且保证没有双方同时获胜的情况)
  保证输入的局面轮到Alice行棋。

输出格式

  对于每组数据,输出一行一个整数,表示当前局面的得分。

样例输入

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

样例输出

3
-4
0

样例说明

  第一组数据:
  Alice将棋子放在左下角(或右下角)后,可以到达问题描述中的局面,得分为3。
  3为Alice行棋后能到达的局面中得分的最大值。
  第二组数据:


  Bob已经获胜(如图),此局面得分为-(3+1)=-4。
  第三组数据:
  井字棋中若双方都采用最优策略,游戏平局,最终得分为0。

数据规模和约定

  对于所有评测用例,1 ≤ T ≤ 5。

答题思路:用DFS模拟两个人下棋的过程,到Alice下棋的时候,Alice可以在棋盘的所有空格中选择一处进行落子,我们找出Alice所有落子中得分最大的那次落子,Bob也类似。

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;

int a[3][3];

//统计还有多少个地方可以落子 
int countEmpty(){
	int cnt = 0; 
	//遍历棋盘的每一格 
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			if(a[i][j] == 0){  //此处还没有被落子过
				cnt++;
			} 
		}
	} 
	return cnt;
} 

//判断当前情况谁是胜利者。返回值:1--Alice胜利,2--Bob胜利,0--暂时未分胜负 
int judgeWinner(){
	int result; 
	//某一行是否有三个相同的棋子。 
	for(int i=0;i<3;i++){
		if(a[i][0] == a[i][1] && a[i][0] == a[i][2] && a[i][0] != 0){
			result = a[i][0]==1?1:2; 
			return result;
		}
	}
	//某一列是否有三个相同的棋子。 
	for(int i=0;i<3;i++){
		if(a[0][i] == a[1][i] && a[0][i] == a[2][i] && a[0][i] != 0){
			result = a[0][i]==1?1:2;
			return result;
		}
	}
	//两条对角线是否有三个相同的棋子。 
	if(a[0][0] == a[1][1] && a[0][0] == a[2][2] && a[0][0] != 0){
		result = a[0][0]==1?1:2;
		return result;
	}
	if(a[0][2] == a[1][1] && a[0][2] == a[2][0] && a[0][2] != 0){
		result = a[0][2]==1?1:2;
		return result;
	}
	return 0; 
}

int DFS2();

//Alice落子 
int DFS1(){
	int winner = judgeWinner(); 
	if(winner != 0){ //有人赢了 
		if(winner == 1){  //Alice赢了 
			return countEmpty() + 1;      //返回Alice的得分。 
		}else{            //Bob赢了  
			return -1*countEmpty() - 1;   //返回Bob的得分 
		} 
	}
	if(countEmpty() == 0){   //如果棋盘已经无处落子了。 
		return 0;
	}
	//寻找在何处落子
	int ans = -5;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			if(a[i][j] == 0){  //此处还没有被落子过
				a[i][j] = 1;   //假设Alice选择此处落子
				int now = DFS2();        //轮到Bob落子 
				ans = max(now,ans);
				a[i][j] = 0;   //相当于悔棋,要重新选择一处进行落子 
			} 
		}
	} 
	return ans;
}

//Bob落子 
int DFS2(){
	int winner = judgeWinner(); 
	if(winner != 0){ //有人赢了 
		if(winner == 1){  //Alice赢了 
			return countEmpty() + 1;      //返回Alice的得分。 
		}else{            //Bob赢了  
			return -1*countEmpty() - 1;   //返回Bob的得分 
		} 
	}
	if(countEmpty() == 0){   //如果棋盘已经无处落子了。 
		return 0;
	}
	//寻找在何处落子
	int ans = 5;
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			if(a[i][j] == 0){  //此处还没有被落子过
				a[i][j] = 2;   //假设Bob选择此处落子
				int now = DFS1();  //轮到Alice落子,now的值是:如果下到此处,该盘棋的最终得分。 
				ans = min(ans,now);//在所有得分中选一个最小得分。     
				a[i][j] = 0;   //相当于悔棋,要重新选择一处进行落子 
			} 
		}
	} 
	return ans;
} 

int main(){
	int n;
	cin>>n;
	while(n--){
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				cin>>a[i][j];
			}
		}
		if(countEmpty() == 9){
			cout<<"0"<<endl;
		}else{
			cout<<DFS1()<<endl;	
		}
	}
	return 0; 
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值