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

题目

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

代码

#include
#include
#include
#include
#include
#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:最近代码风格变化的略快略多啊。。。

你可能感兴趣的:(博弈论)