# DFS# Backtracking# Game Theory

d576 - 辭典遊戲

🔗 前往 ZeroJudge 原題

題目描述

題目描述了一個兩人輪流從一個 N x N 的棋盤上取數字的遊戲。玩家 A 總是先從第一列開始,玩家 B 則從玩家 A 取走數字的那一列開始。遊戲持續進行,直到其中一方無法再取數字為止。最終,總和較高的玩家獲勝。題目要求計算所有可能的遊戲進行方式中,A 獲勝、B 獲勝和平手的次數。

解題思路

這道題可以使用深度優先搜尋 (DFS) 來模擬所有可能的遊戲過程。dfs 函數模擬了遊戲的進行,參數 xy 代表當前棋盤上的位置,asbs 分別代表 A 和 B 取得的總和,round 記錄了當前是第幾回合(奇數回合 A 走,偶數回合 B 走)。

dfs 函數中,首先標記當前位置為已訪問,然後根據回合數更新 A 或 B 的總和。接著,遞迴地探索所有可能的下一個位置。如果沒有可行的下一個位置,則判斷 A 和 B 的總和,並更新對應的獲勝次數。最後,將當前位置標記為未訪問,以便回溯到上一層。

主函數中,讀取棋盤的數字,初始化獲勝次數,然後從第一列的每個位置開始進行 DFS 搜尋。最後,輸出 A 獲勝、B 獲勝和平手的次數。

複雜度分析

  • 時間複雜度: O(N! * N!)。在最壞的情況下,需要探索所有可能的遊戲過程,這涉及到 N! 種可能的 A 的走法,以及在每種 A 的走法下,B 的 N! 種走法。
  • 空間複雜度: O(N * N)。主要用於儲存棋盤狀態 pnp,以及 DFS 的遞迴堆疊。

程式碼

#include <iostream>
using namespace std;
int p[5][5],n,awin,bwin,tie,np[5][5];
inline void dfs(int x,int y,int as,int bs,int round){
	int stp=0;
	np[x][y]=1;
	if(round&1){
		as+=p[x][y];
		for(int i=0;i<n;++i)
			if(!np[i][y]){
				dfs(i,y,as,bs,round+1);
				stp=1;
	 		}
	}
	else{
		bs+=p[x][y];
		for(int i=0;i<n;++i)
			if(!np[x][i]){
				dfs(x,i,as,bs,round+1);
				stp=1;
			}
	}
	if(stp==0){
		if(as>bs)
			++awin;
		else if(bs>as)
			++bwin;
		else
			++tie;
	}
	np[x][y]=0;
	return;
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	while(cin >> n){
		for(int i=0;i<5;++i)
			for(int j=0;j<5;++j)
				np[i][j]=p[i][j]=0;
		for(int i=0;i<n;++i)
			for(int j=0;j<n;++j)
				cin >> p[i][j];
		awin=bwin=tie=0;
		for(int i=0;i<n;++i)
			dfs(0,i,0,0,1);
		cout << awin << " " << bwin << " " << tie << "\n";
	}
}

Discussion