Codeforces 936B

题意略。

思路:

图论里掺杂了一些动态规划。

有几个注意点:

1.dp时状态的设计:因为我们要寻求的是出度为0并且可以从起点走奇数步抵达的点,由于同一个点可以通过多种方式到达。

并且我们在获得奇数步点的时候,需要偶数步点作为支撑,所以visit[ i ][ j ]表示第i个点能否具备j状态(0、1),也即奇偶数步。

2.dp采用spfa,也即刷表法。在使用spfa时,最好将点和状态一起打包。

3.判断有向图是否存在环,可以采用拓扑排序。

 

详见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

struct node{
    int v,state;
    node(int v = 0,int state = 0){
        this->v = v;
        this->state = state;
    }
};

int visit[maxn][2],out[maxn],indegree[maxn],n,m,s;
bool vis[maxn];
vector<int> graph[maxn],vs;
queue<node> que;
queue<int> topque;

void spfa(){
    memset(visit,0,sizeof(visit));
    visit[s][0] = -1;
    que.push(node(s,0));
    while(que.size()){
        node nd = que.front();
        que.pop();
        int v = nd.v,state = nd.state;
        for(int i = 0;i < graph[v].size();++i){
            int u = graph[v][i];
            if(!visit[u][state ^ 1]){
                visit[u][state ^ 1] = v;
                que.push(node(u,state ^ 1));
            }
        }
    }
}
bool judcircle(){
    int cnt = 0;
    for(int i = 1;i <= n;++i){
        if(!visit[i][0] && !visit[i][1]) continue;
        if(indegree[i] == 0)
            topque.push(i);
        ++cnt;
    }
    while(topque.size()){
        int v = topque.front();
        topque.pop();
        --cnt;
        for(int i = 0;i < graph[v].size();++i){
            int u = graph[v][i];
            indegree[u] -= 1;
            if(indegree[u] == 0) topque.push(u);
        }
    }
    return cnt > 0;
}
void dfs(int cur){
    for(int i = 0;i < graph[cur].size();++i){
        int v = graph[cur][i];
        ++indegree[v];
        if(indegree[v] == 1){
            dfs(v);
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    memset(indegree,0,sizeof(indegree));
    for(int i = 1,to;i <= n;++i){
        scanf("%d",&out[i]);
        for(int j = 0;j < out[i];++j){
            scanf("%d",&to);
            graph[i].push_back(to);
        }
    }
    scanf("%d",&s);
    dfs(s);
    spfa();
    bool circle = judcircle();
    bool jud = false;
    for(int i = 1;i <= n && !jud;++i){
        if(!out[i] && visit[i][1] != 0){
            jud = true;
            printf("Win\n");
            int now = 1;
            for(int v = i;v != -1;v = visit[v][now],now = now ^ 1){
                vs.push_back(v);
            }
            for(int j = vs.size() - 1;j >= 0;--j){
                printf("%d%c",vs[j],j ? ' ' : '\n');
            }
        }
    }
    if(!jud){
        printf("%s\n",circle ? "Draw" : "Lose");
    }
    return 0;
}

/*
6 6
1 2
2 3 4
1 5
1 5
1 6
0
3
*/

 

posted @ 2018-08-07 19:01  温和的提比略  阅读(107)  评论(0编辑  收藏  举报