poj 2762 Going from u to v or from v to u(targan缩点+拓扑排序)

题目链接:http://poj.org/problem?id=2762

给定顶点和边的关系,问是否对于任意的顶点x和y,总存在x到y的路径或y到x的路径,一开始看成和的关系,判断只有一个连通分量。

如果是或的话,就是对于缩点后的图看看能不能找到一条路径贯穿所有的点,用拓扑排序更新出到达每个顶点最多能有几个顶点。然后如果顶点个数=强连通分量数,那么就是符合题意的。


附上测试数据和代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;

const int maxn = 1002;
const int maxm = 6005;
int n, m;

int head[maxn];
struct E {
    int to;
    int next;
} edge[maxm];

int dfn[maxn];
int low[maxn];
bool instack[maxn];
int stap[maxn];
int belong[maxn];
vector<int> G[maxn];
int indeg[maxn];
int index, cur, cnt, eid;
int dis[maxn];

void addedge(int from, int to) {
    edge[eid].to = to;
    edge[eid].next = head[from];
    head[from] = eid ++;
}

void targan(int v) {
    dfn[v] = low[v] = ++index;
    instack[v] = true;
    stap[++cur] = v;
    for (int i = head[v]; ~i; i = edge[i].next) {
        int to = edge[i].to;
        if(!dfn[to]) {
            targan(to);
            low[v] = min(low[v], low[to]);
        } else if(instack[to]) {
            low[v] = min(low[v], dfn[to]);
        }
    }
    if(dfn[v] == low[v]) {
        cnt ++;
        int j;
        do {
            j = stap[cur--];
            instack[j] = false;
            belong[j] = cnt;
        } while (j != v);
    }
}
void suo() {
    for(int i = 1; i <= cnt; i ++) {
        G[i].clear();
        indeg[i] = 0;
    }
    for (int i = 1; i <= n; i ++) {
        for (int j = head[i]; ~j; j = edge[j].next) {
            if(belong[i] != belong[edge[j].to]) {
                G[belong[i]].push_back(belong[edge[j].to]);
                indeg[belong[edge[j].to]] ++;
            }
        }
    }
}
bool topo() {
    queue<int> que;
    for (int i = 1; i <= cnt; i ++) {
        if(indeg[i] == 0) {
            que.push(i);
            dis[i] = 1;
        }
        else {
            dis[i] = 0;
        }
    }
    while(!que.empty()) {
        int cur = que.front();
        que.pop();
        for(int i = 0; i < G[cur].size(); i ++) {
            int to = G[cur][i];
            dis[to] = max(dis[to], dis[cur] + 1);
            indeg[to] --;
            if(indeg[to] == 0) {
                que.push(to);
            }
        }
    }
    for(int i = 1; i <= cnt; i ++) {
        if(dis[i] == cnt) {
            return true;
        }
    }
    return false;
}
int main() {
    int x, y, t;
//    freopen("1.in", "r", stdin);
    scanf("%d", &t);
    while (t --) {
        scanf("%d%d",&n, &m);
        memset(head, -1, sizeof(head));
        memset(dfn, 0, sizeof(dfn));
        memset(instack, false, sizeof(instack));
        eid = 0;
        for (int i = 0; i < m; i ++) {
            scanf ("%d%d", &x, &y);
            addedge(x, y);
        }
        cur = index = cnt = 0;
        for (int i = 1; i <= n; i++) {
            if(!dfn[i]) {
                targan(i);
            }
        }
        suo();
        if(topo()) {
            printf("Yes\n");
        }
        else {
            printf("No\n");
        }
    }
    return 0;
}

/*
11

8 10
1 5
6 3
2 7
7 8
3 6
8 2
2 1
4 6
7 3
6 5

5 8
1 2
2 3
3 4
1 3
1 4
2 4
4 5
5 4

6 10
6 3
2 5
4 6
3 6
2 6
6 1
1 5
3 2
4 1
5 3

7 8
1 2
3 1
3 2
2 4
4 7
4 5
5 6
6 4

3 3
1 2
2 3
3 1

5 5
1 2
2 3
3 1
3 4
4 5

4 4
1 2
2 3
3 1
4 3

4 4
1 2
1 3
2 4
3 4

3 3
1 2
2 1
3 1

4 4
1 2
1 3
2 4
3 4

4 5
1 2
2 3
2 4
1 3
1 4

No
Yes
Yes
Yes
Yes
Yes
Yes
No
Yes
No
No

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值