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; 
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章