HDU1425 A Chess Game

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1524

思路:题目就是给你一个拓扑图,然后指定点的位置放棋子,然后两人轮流移动棋子(题目中的边的关系),直到一方不能移动。

SG函数裸题,之前接触的两道一个是推的关系,一个是取石子的。这个比较明显的就是出度为0的点,sg值为0。然后深搜得到其他点的sg值,棋子的异或和为0 则P必败,否则N必胜

由于递归写的很不好,导致没过。最开始竟然用队列随便写了一个。(TLE),后来尝试用dfs写了,WA,迫于无奈只好看题解了(果真就是dfs)  后面附有错误代码

AC代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
using namespace std;
#define in freopen("in.txt", "r", stdin);
typedef long long ll;
const int inf = 0x3f3f3f3f;

vector<int> G[1010];
int sg[1010];
int n, xi, u, v, m, x;
int dfs(int id) { //为什么感觉不是太难写,自己就是写不出来。   T_T !!!
	if(sg[id] != -1) return sg[id];//已经有了直接返回 
	bool vis[1010];//标记,求mex 
	memset(vis, false, sizeof(vis));
	for(int i = 0; i < G[id].size(); i++) {
		sg[G[id][i]] = dfs(G[id][i]);//递归求出后继sg值 
		vis[sg[G[id][i]]]= true;//标记后继的sg值 
	}
	for(int i = 0; ; i++) {
		if(!vis[i]) {
			return sg[id] = i;//求自己的sg值 
		}
	}
}

int main() {
	while(~scanf("%d", &n)) {
		memset(G, 0, sizeof(G));
		for(int i = 0; i < n; i++) {
			scanf("%d", &xi);
			while(xi--) {//存图 
				scanf("%d", &v);
				G[i].push_back(v);
			}
		}
		memset(sg, -1, sizeof(sg));
		while(scanf("%d", &m) && m) {
			int sum = 0;
			while(m--) {//异或和 
				scanf("%d", &x);
				sum ^= dfs(x);
			}
			if(sum)
				printf("WIN\n");
			else
				printf("LOSE\n");
		}
	}
} 

瞎写的队列代码(TLE)

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
using namespace std;
#define in freopen("in.txt", "r", stdin);
typedef long long ll;
const int inf = 0x3f3f3f3f;

vector<int> G[1010];
int sg[1010];
int n, xi, u, v, m, x;

void SG() {
	queue<int> q;
	for(int i = 0; i < n; i++) {
		if(G[i].size() == 0)
			sg[i] = 0;
		else q.push(i);//需要求的点i 
	}
	bool vis[1010];
	while(!q.empty()) 
		memset(vis, false, sizeof(vis));
		int u = q.front();
		bool flag = false;
		for(int j = 0; j < G[u].size(); j++) { 
			if(sg[G[u][j]] != -1) {//如果后继有一个不知道的就换 
				vis[sg[G[u][j]]] = true;
			} else {
				flag = true;
				q.push(u);
				q.pop();
			}
		}
		if(flag == false) {//说明这个点的sg值可以求 
			for(int j = 0; j <= 1010; j++) {
				if(vis[j] == false) {
					sg[u] = j;
					break;
				}
			}
			q.pop();
		}
	}
}

int main() {
	while(~scanf("%d", &n)) {
		memset(G, 0, sizeof(G));
		for(int i = 0; i < n; i++) {
			scanf("%d", &xi);
			if(xi == 0)
				continue;
			else {
				while(xi--) {
					scanf("%d", &v);
					G[i].push_back(v);
				}
			}
		}
		memset(sg, -1, sizeof(sg));
		SG();
		while(~scanf("%d", &m) && m) {
			int sum = 0;
			while(m--) {
				scanf("%d", &x);
				sum ^= sg[x];
			}
			if(sum)
				printf("WIN\n");
			else
				printf("LOSE\n");
		}
	}
} 

自己写的错误DFS代码:

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
using namespace std;
#define in freopen("in.txt", "r", stdin);
typedef long long ll;
const int inf = 0x3f3f3f3f;

vector<int> G[1010];
int sg[1010], indegree[1010];
int n, xi, u, v, m, x, topu;
vector<int> GB[1010];//该点的 后继值 
void SG(int id) {
	for(int i = 0; i < G[id].size(); i++) {//我刚开始也写的bool vis[maxn]  但是我以为这个vis的状态会被破坏 T_T 
		if(sg[G[id][i]] != -1)
			GB[id].push_back(sg[G[id][i]]);
		else {
			SG(G[id][i]);//瞎写我以为这样求下去,sg[G[id][i]]的值就有了 但是我还是感觉就有了。。。。 
			GB[id].push_back(sg[G[id][i]]);
		}
	}
	sg[id] = *min_element(GB[id].begin(), GB[id].end()) - 1;//直接求sg值 
}

int main() {
	while(~scanf("%d", &n)) {
		memset(G, 0, sizeof(G));
		memset(GB, 0, sizeof(GB));
		memset(indegree, 0, sizeof(indegree));
		for(int i = 0; i < n; i++) {
			scanf("%d", &xi);
			if(xi == 0)
				continue;
			else {
				while(xi--) {
					scanf("%d", &v);
					G[i].push_back(v);
					indegree[v]++;//因为是一个图,我就打算从根节点开始往下搜 
				}
			}
		}
		memset(sg, -1, sizeof(sg));
		for(int i = 0; i < n; i++) {
			if(G[i].size() == 0)
				sg[i] = 0;
			else if(indegree[i] == 0)
				topu = i;//根节点 
		}
		SG(topu);
		while(~scanf("%d", &m) && m) {
			int sum = 0;
			while(m--) {
				scanf("%d", &x);
				sum ^= sg[x];
			}
			if(sum)
				printf("WIN\n");
			else
				printf("LOSE\n");
		}
	}
} 

猜你喜欢

转载自blog.csdn.net/qq_40932661/article/details/81334000