SRM588 D1-Hard GameInDarknessDiv1

問題

2次元上のn*mセルからなる盤面にアリスとボブのトークンが1つずつ配置されている。盤面には壁があり、壁でないセルの隣接関係をグラフにすると木になっている。
アリスとボブが交互にトークンを隣接したセルに移動させる。もしアリスとボブのトークンが同じセルに入るとアリスの勝ち、100000手逃げ切ることができればボブの勝ちとなる。
ただし、アリスには双方の初期位置しかわからず、ボブの移動経路は知ることができない。また、ボブはアリスがゲーム中にどのようにトークンを移動させるかがすべてわかっている。
この条件のもとで、双方が最善な手を取った時にどちらが勝利するかを求めよ。

  • 2 <= n, m <= 50

解法

(System Testは通せたもののちゃんと証明できていないので嘘解法かも)
盤面が十分に小さいので100000手逃げ切ることができる→永遠に逃げ続けられると考える。
ボブがアリスから逃げ切るためには、その頂点を取り除いたときに、もともとそれと隣接していた頂点を根とした木の深さが3以上となる頂点が3つ以上ある頂点に、アリスより2手早く到達する必要がある。
そのような条件を満たす頂点が存在するならボブが勝ち、存在しなければアリスが勝つ。

コード

const int INF = 1000000000;
const int dx[] = { 1, 0, -1, 0 };
const int dy[] = { 0, -1, 0, 1 };

bool between(int a, int b, int c){
	return a <= b && b < c;
}

class GameInDarknessDiv1 {
	bool dfs(int d, int u, int p, const vector< vector<int> > &conn) const {
		if(d == 0){ return true; }
		for(int i = 0; i < conn[u].size(); ++i){
			const int v = conn[u][i];
			if(v == p){ continue; }
			if(dfs(d - 1, v, u, conn)){ return true; }
		}
		return false;
	}
	vector<int> bfs(int root, const vector< vector<int> > &conn) const {
		const int n = conn.size();
		vector<int> dist(n, INF);
		dist[root] = 0;
		queue<int> q;
		q.push(root);
		while(!q.empty()){
			const int u = q.front();
			q.pop();
			for(int i = 0; i < conn[u].size(); ++i){
				const int v = conn[u][i];
				if(dist[v] < INF){ continue; }
				dist[v] = dist[u] + 1;
				q.push(v);
			}
		}
		return dist;
	}
public:
	string check(vector <string> field){
		const int n = field.size(), m = field[0].size();
		vector< vector<int> > id(n, vector<int>(m, -1));
		int k = 0, ai = 0, bi = 0;
		for(int i = 0; i < n; ++i){
			for(int j = 0; j < m; ++j){
				if(field[i][j] == '#'){ continue; }
				if(field[i][j] == 'A'){ ai = k; }
				if(field[i][j] == 'B'){ bi = k; }
				id[i][j] = k++;
			}
		}
		vector< vector<int> > conn(k);
		for(int i = 0; i < n; ++i){
			for(int j = 0; j < m; ++j){
				if(id[i][j] < 0){ continue; }
				for(int d = 0; d < 4; ++d){
					const int y = i + dy[d], x = j + dx[d];
					if(!between(0, y, n) || !between(0, x, m)){ continue; }
					if(id[y][x] < 0){ continue; }
					conn[id[i][j]].push_back(id[y][x]);
				}
			}
		}
		vector<int> adist = bfs(ai, conn), bdist = bfs(bi, conn);
		if(adist[bi] <= 1){ return "Alice wins"; }
		for(int i = 0; i < k; ++i){
			if(conn[i].size() < 3){ continue; }
			int num = 0;
			for(int j = 0; j < conn[i].size(); ++j){
				if(dfs(2, conn[i][j], i, conn)){ ++num; }
			}
			if(num >= 3){
				if(adist[i] > bdist[i] + 1){
					return "Bob wins";
				}
			}
		}
		return "Alice wins";
	}
};