您的位置:首页 > 其它

博弈论初探----DAG上的NIM

2016-07-17 23:37 323 查看

题目

给定一个DAG,起点1出有一个棋子,先手后手依次将他向出边移动,最先无法移动的人输,求先手是否必胜。
//因为只要能转移到任意的对手的必败态,便为必胜态,反之为必败态,故只会有必胜/必败态存在。


代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 10010
#define maxm 10010
using namespace std;

struct Edge{
int u;
int v;
Edge *next;
} edge[maxm];

bool win[maxn];
int n, m;
int out_edge[maxn];
int topo_queue[maxn], q_end = 0, q_begin = 0;
Edge *V[maxn];

int main() {
cin >> n >> m;
memset(out_edge, 0, sizeof(out_edge));
for (int i = 1; i <= m ; i++) {
cin >> edge[i].u >> edge[i].v;
edge[i].next = V[edge[i].v];
V[edge[i].v] = &edge[i];
out_edge[edge[i].u]++;
}//邻接表储存,同时记录出度。
for(int i = 1; i <= n; i++)
if(!out_edge[i]) topo_queue[q_end++] = i;//将所有出度为0的点加入处理队列中
for(int i = 0; i < q_end; i++)
win[i] = false;                         //所有点初始为先手无法必胜,因先手到达无法走的点即败
while(q_begin < q_end) {
int i = topo_queue[q_begin++];
win[i] = !win[i];                       //win[i]表示以i点位起点,先手是否必胜,这里将之前表示的能否到达先手必败态的节点 反转为先手是否必胜
for(Edge *e = V[i]; e; e = e->next) {
if(--out_edge[e->u] == 0) {
win[e->u] = win[i] || win[e->u];//只要以此节点为起点走能转移到任意一个先手必胜态的起点,此节点先手必败。
// 这里记录的是能否到达一个先手必胜态的起点。当此节点出队时再反转结果

topo_queue[q_end++] = e->u;
}
} //toposort删边过程
}     //toposort过程
if(win[1]) cout << "win";
else cout << "lose";
return 0;
}


ps:最近代码风格变化的略快略多啊。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  博弈论