UVALive 6195 The Dueling Philosophers Problem 强连通缩点+拓扑序

题目链接:点击打开链接

给定n个点m条限制

下面限制 u->v

表示u必须排在v前面,问把n个数排成一排有多少种方法。

若有0种输出0

1种输出1

多种输出2

**边的数量题目里少了个0==

思路:

0种就是有环,缩点一下判断强连通分量是不是n个。

1种就是拓扑序时队列里任何时刻都只有一个点


否则就是2种

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include <queue>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;
const int N = 1000000;
const int M = 1000010;
struct Edge{
    int from, to, nex;
}edge[M];
int head[N], edgenum;
void add(int u, int v){
    Edge E = {u,v,head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
int DFN[N], Low[N], Stack[N], top, Time;
int taj;
bool Instack[N];
void tarjan(int u, int fa){
    DFN[u] = Low[u] = ++Time;
    Stack[top++] = u;
    Instack[u] = 1;
    for(int i = head[u]; ~i; i = edge[i].nex){
        int v = edge[i].to;
        if(DFN[v] == -1)
        {
            tarjan(v, u);
            Low[u] = min(Low[u], Low[v]);
        }
        else if(Instack[v])Low[u] = min(Low[u], DFN[v]);
    }
    if(Low[u] == DFN[u])
    {
        int now ;
        taj++;
        do{
            now = Stack[--top];
            Instack[now] = 0;
        }while(now != u);
    }
}
void tarjan_init(int all){
    for(int i = 1; i <= all; i++)
    {
        DFN[i] = -1;
        Instack[i] = 0;
    }
    top = Time = taj = 0;
    for(int i = 1; i <= all; i++)
        if(DFN[i] == -1)
            tarjan(i, i);
}
int in[N];
void suodian(){
    for(int i = 1; i <= taj; i++) in[i] = 0;
    for(int i= 0; i < edgenum; i++)
        in[edge[i].to]++;
}
void init(){memset(head, -1, sizeof head); edgenum = 0;}
int n, m;
int topsort(int x){
    queue<int> q;
    q.push(x);
    int inque = 0;
    while(!q.empty()){
        int u = q.front(); q.pop();
        inque ++;
        for(int i = head[u]; ~i; i = edge[i].nex){
            int v = edge[i].to;
            in[v]--;
            if(in[v] == 0)
                q.push(v);
        }
        if((int)q.size() > 1)
            return 2;
    }
    if(inque != n)
        return 2;
    return 1;
}
int work(){
    tarjan_init(n);
    if(taj != n)return 0;
    suodian();
    int ru = -1;
    for(int i = 1; i <= n; i++)
        if(in[i] == 0)
        {
            if(ru == -1) ru = i;
            else
                return 2;
        }
    if(ru == -1) return 0;
    return topsort(ru);
}
void input(){
    init();
 //   if(n>=N||n<1||m>=M||m<1)while(1);
    while(m--){
        int u, v;
        scanf("%d %d", &u, &v);
        if(u<1||u>n||v<1||v>n||u==v)continue;
        add(u, v);
    }
}
int main(){
    while(cin>>n>>m, n+m){
        input();
        cout<<work()<<endl;
    }
    return 0;
}
/*
5 4
1 5
5 2
3 2
4 3
5 4
3 1
4 2
1 5
5 4
2 2
1 2
2 1

4 4
1 2
2 3
3 4
4 1

1 0

0 0

*/


你可能感兴趣的:(UVALive 6195 The Dueling Philosophers Problem 强连通缩点+拓扑序)