POJ2425,组合游戏

题目链接:A Chess Game
首先需要了解SG函数及SG定理:博弈论 SG函数
Nim游戏与SG函数 ——博弈论小结
在了解了以上之后就好做了。首先对于一个有向图来说,每个点都有一个sg函数值,如果该值为0,则此位置为先手必败即P位置,否则为先手必胜即N位置。而所有的棋子的位置的sg值异或之和为0即输,否则则赢。现在的目标就是求每个点的sg值,按照sg函数的定义,求出每个点的sg值。注意:求sg值是自底向上的,我这里用了两种方法,一种为dfs,一种为拓扑排序。
代码如下:
方法一:

/*************************************************************************
	> File Name: main.cpp
	> Author:Eagles 
	> Mail:None 
	> Created Time: 2018年11月06日 星期二 11时23分33秒
	> Description:POJ2425 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 1005
struct edge
{
    int to;
    int nex;
}E[N*N];
int head[N];
int sg[N];
bool vis[N];
int n,cnt;

void addEdge(int a, int b)加边
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

void init()//初始化
{
    memset(head,-1,sizeof(head));
    memset(sg,0,sizeof(sg));
    memset(vis,false,sizeof(vis));

    cnt=0;

    for (int i=0; i<n; i++)
    {
        int num;
        scanf("%d",&num);

        while (num--)
        {
            int to;
            scanf("%d",&to);
            addEdge(i,to);
        }
    }
}

void dfs(int dot)
{
    vis[dot]=true;

    if (head[dot] == -1)
    {
        sg[dot]=0;
        return ;
    }

    int hash_val[N];
    
    memset(hash_val,0,sizeof(hash_val));

    for (int i=head[dot]; i!=-1; i=E[i].nex)
    {
        if (!vis[E[i].to])
        {
            dfs(E[i].to);
        }
        hash_val[sg[E[i].to]]=1;
    }
    
    for (int i=0; i<n; i++)
    {
        if (hash_val[i] == 0)
        {
            sg[dot]=i;
            break;
        }
    }

}

void solve()
{
    for (int i=0; i<n; i++)
    {
        if (!vis[i])
            dfs(i);
    }

    int num;

    while (~scanf("%d",&num)&&num)
    {
        int ans=0;
        while (num--)
        {
            int to;
            scanf("%d",&to);
            ans^=sg[to];
        }

        printf("%s\n",ans==0?"LOSE":"WIN");
    }
}

void print()
{
    for (int i=0; i<n; i++)
        if (!vis[i])
            dfs(i);
    for (int i=0; i<n; i++)
        printf("%d ",sg[i]);
    printf("\n");
}
int main()
{
    while (~scanf("%d",&n))
    {
        init();
        solve();
    }
    return 0;
}

方法二:

/*************************************************************************
	> File Name: main.cpp
	> Author:Eagles 
	> Mail:None 
	> Created Time: 2018年11月06日 星期二 19时48分51秒
	> Description:poj2425 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
#define N 1005
struct edge
{
    int to;
    int nex;
    int val;
}E[N*N];
int head[N];
int sg[N];
int hash_val[N];
int indeg[N];//入度
queue<int>q;//用来存拓扑排序后的序列
int n,cnt;

void addEdge(int a, int b, int val)
{
    E[cnt].to=b;
    E[cnt].val=val;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;

    memset(sg,0,sizeof(head));
    memset(hash_val,0,sizeof(hash_val));
    memset(indeg,0,sizeof(indeg));

    while (!q.empty())
        q.pop();

    for (int i=0; i<n; i++)
    {
        int num;
        scanf("%d",&num);
        
        while (num--)
        {
            int a;
            scanf("%d",&a);
            addEdge(i,a,1);//本来的边
            addEdge(a,i,-1);//加了一条反向的“虚边”,为了拓扑排序
            indeg[i]++;//拓扑排序反向
        }
    }
}

void top_sort()//拓扑排序
{
    queue<int>tmp_q;

    for (int i=0; i<n; i++)
        if (indeg[i]==0)
            tmp_q.push(i);

    while (!tmp_q.empty())
    {
        int cur=tmp_q.front();
        tmp_q.pop();

        q.push(cur);

        for (int i=head[cur]; i!=-1; i=E[i].nex)
        {
            if (E[i].val == -1)
            {
                indeg[E[i].to]--;

                if (indeg[E[i].to] == 0)
                    tmp_q.push(E[i].to);
            }
        }
    }
}

void sg_val()
{
    while (!q.empty())//自底向上计算sg值,最前面的肯定是出度为0的点
    {
        int cur=q.front();
        q.pop();

        memset(hash_val,0,sizeof(hash_val));

        for (int i=head[cur]; i!=-1; i=E[i].nex)
        {
            if (E[i].val == 1)
            {
                hash_val[sg[E[i].to]]=1;    
            }
        }

        for (int i=0; i<n; i++)
        {
            if (hash_val[i] == 0)
            {
                sg[cur]=i;
                break;
            }
        }
    }
}

void solve()
{
    top_sort();
    sg_val();

    int num;

    while (~scanf("%d",&num)&&num)
    {
        int ans=0;

        while (num--)
        {
            int a;
            scanf("%d",&a);

            ans^=sg[a];
        }

        printf("%s\n",ans==0?"LOSE":"WIN");
    }
}

void print()
{
    top_sort();
    sg_val();

    for (int i=0; i<n; i++)
        printf("%d ",sg[i]);
    
    printf("\n");
}

int main()
{
    while (~scanf("%d",&n))
    {
        init();
        solve();
    }
    return 0;
}

发布了45 篇原创文章 · 获赞 2 · 访问量 3070

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/83794596