Codeforces Round #467 (Div. 2) D. Sleepy Game

题目链接:http://codeforces.com/contest/937/problem/D

D. Sleepy Game
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Petya and Vasya arranged a game. The game runs by the following rules. Players have a directed graph consisting of n vertices and medges. One of the vertices contains a chip. Initially the chip is located at vertex s. Players take turns moving the chip along some edge of the graph. Petya goes first. Player who can't move the chip loses. If the game lasts for 106 turns the draw is announced.

Vasya was performing big laboratory work in "Spelling and parts of speech" at night before the game, so he fell asleep at the very beginning of the game. Petya decided to take the advantage of this situation and make both Petya's and Vasya's moves.

Your task is to help Petya find out if he can win the game or at least draw a tie.

Input

The first line of input contain two integers n and m — the number of vertices and the number of edges in the graph (2 ≤ n ≤ 1050 ≤ m ≤ 2·105).

The next n lines contain the information about edges of the graph. i-th line (1 ≤ i ≤ n) contains nonnegative integer ci — number of vertices such that there is an edge from i to these vertices and ci distinct integers ai, j — indices of these vertices (1 ≤ ai, j ≤ nai, j ≠ i).

It is guaranteed that the total sum of ci equals to m.

The next line contains index of vertex s — the initial position of the chip (1 ≤ s ≤ n).

Output

If Petya can win print «Win» in the first line. In the next line print numbers v1, v2, ..., vk (1 ≤ k ≤ 106) — the sequence of vertices Petya should visit for the winning. Vertex v1 should coincide with s. For i = 1... k - 1 there should be an edge from vi to vi + 1 in the graph. There must be no possible move from vertex vk. The sequence should be such that Petya wins the game.

If Petya can't win but can draw a tie, print «Draw» in the only line. Otherwise print «Lose».

Examples
input
Copy
5 6
2 2 3
2 4 5
1 4
1 5
0
1
output
Win
1 2 4 5 
input
Copy
3 2
1 3
1 1
0
2
output
Lose
input
Copy
2 2
1 2
1 1
1
output
Draw

分析:

好久不做题,手都生了。这道题是一道有向图的题。题意简单来说就是,给你一张有向图(不保证图连通,因为m可以等于0),首先问你从一个特定的点出发能不能走入一个环,然后问你从特定的点出发,能不能走到一个出度为0的点,使得这个出度为0的点距出发点距离为奇数(因为先手替后手走,所以只要存在一个就赢了)。

首先说怎么判断第一个问题:如果是问你一个有向图中是否有一个环,那么直接用拓扑排序就可以了。可是如果从一个特定的点出发,就要考虑dfs。一个点的状态有三种,vis=1(这个点所有的儿子已经遍历完),vis=-1(这个点没有被遍历过),vis=0(这个点已经被遍历过,但是他的儿子没有被遍历完),这样,当你扩展一个节点时,如果走到了一个vis=0的节点,那就说明这个点一定是从子孙节点又遍历回去了,所以就有了一个环。

对于第二个问题就比较简单了,开一个二维数组dp[maxn][2],dp[x][0]代表如果存在一条路径,使得出发节点st到x的长度为偶数,那么dp[x][0]就是x节点的上一个节点。同理,dp[x][1]代表如果存在一条路径,使得出发节点st到x的长度为奇数,那么dp[x][1]就是x节点的上一个节点。也就是说dp[now][0]可以去更新dp[next][1],dp[now][1]可以更新dp[next][0],而且不必要重复更新。这样一来,复杂度最多为O(2*n)。


代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1e5+10;
vector<int>p[maxn];
int dp[maxn][2],path[maxn];
int vis[maxn];
int type,ans;
bool hasDraw;
void init()
{
    for(int i=0;i<maxn;i++)
        p[i].clear();
    memset(dp,-1,sizeof(dp));
    memset(vis,-1,sizeof(vis));
    hasDraw=0;
    type=0;
    ans=-1;
}
void dfs(int now)//dfs遍历是否有环
{
    if(hasDraw)
        return;
    for(int i=0;i<p[now].size();i++)
    {
       int next=p[now][i];
       if(vis[next]==-1)//next没有被遍历过
       {
           vis[next]=0;
           dfs(next);
       }
       else if(vis[next]==0)//next的儿子节点没有遍历完,则一定是从儿子节点回去的
       {
           hasDraw=1;
            return;
       }
       else if(vis[next]==1)
        continue;
    }
    //遍历完,vis置为1
    vis[now]=1;
    return;
}


void findans(int now)
{
    int e=p[now].size();
    if((e==0)&&(dp[now][1]!=-1))
    {
        ans=now;
        return ;
    }
    for(int i=0;i<p[now].size();i++)
    {
        int next=p[now][i];
        if((dp[now][0]!=-1)&&(dp[next][1]==-1))//可更新
        {
            dp[next][1]=now;
            findans(next);
        }
        if((dp[now][1]!=-1)&&(dp[next][0]==-1))
        {
            dp[next][0]=now;
            findans(next);
        }
    }


    return ;
}
int main()
{
    int n,m,num,a,st,en;
    cin>>n>>m;
    init();
    for(int i=1;i<=n;i++)
    {
        cin>>num;
        while(num--)
        {
            cin>>a;
            p[i].push_back(a);
        }
    }
    cin>>st;
    vis[st]=0;
    dfs(st);
    if(hasDraw)
        type=1;
    dp[st][0]=0;
    findans(st);
    if(ans==-1)
    {
        if(type==1)
            cout<<"Draw"<<endl;
        else
            cout<<"Lose"<<endl;
    }
    else
    {
        int cnt=0;
        int state=0;
        for(int i=ans;i!=0;)
        {
            path[cnt]=i;
            cnt++;
            if(state==1)
            {
                i=dp[i][0];
                state=0;
            }
            else
            {
                i=dp[i][1];
                state=1;
            }
        }
        cout<<"Win"<<endl;
        for(int i=cnt-1;i>=0;i--)
            cout<<path[i]<<" ";
        cout<<endl;


    }




}

猜你喜欢

转载自blog.csdn.net/qq_39004117/article/details/79518699