Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 27198 | Accepted: 10963 |
Description
Input
Output
Sample Input
3 3 1 2 2 1 2 3
Sample Output
1
Hint
题意:每个奶牛有梦想成为牧群中最受奶牛仰慕的奶牛, 在牧群中, 有N头奶牛 给定M对有序对(A, B),表示A仰慕B。由于仰慕关系具有传递性,也就是说,如果A仰慕B,B仰慕C, 则A也仰慕C,计算牧群中受每头牛仰慕的奶牛数量
解析:
如果强连通分量中一头牛A受到强连通分量外另一头牛B的仰慕,则该强连通分量中的每一头牛都受到B的仰慕;
如果强连通分量中一头牛A仰慕强连通分量外的另一头牛B,则强连通分量中的每一头牛都仰慕B。
所以将【每个强连通分支】缩成一个点,记录每个【缩点】的出度,并构造新图。统计出度为0的【缩点】的个数,如果正好为1,则说明该【缩点】能被其他所有【缩点】走到。该【缩点】包含点的个数就是我们所求答案。
简化来说:
给出一个有向图,求一共有多少个点,满足这样的条件:所有其它的点都可以到达这个点。
强连通分支+缩点,然后统计每个【缩点】的出度,如果只有一个为0,则输出其内部点的个数,如果有多个为0,说明没有答案,输出0。
#include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> #define maxn 10000 + 1000 #define maxm 50000 + 5000 using namespace std; int n, m; struct node { int u, v, next; }; node edge[maxm]; int head[maxn], cnt; int low[maxn], dfn[maxn]; int dfs_clock; int Stack[maxn]; bool Instack[maxn]; int top; int Belong[maxn] , scc_clock; int out[maxn]; void init(){ cnt = 0; memset(head, -1, sizeof(head)); } void addedge(int u, int v){ edge[cnt] = {u, v, head[u]}; head[u] = cnt++; } void getmap(){ while(m--){ int a, b; scanf("%d%d", &a, &b); addedge(a, b); } } void tarjan(int u, int per){ int v; low[u] = dfn[u] = ++dfs_clock; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; i != -1; i = edge[i].next){ v = edge[i].v; if(!dfn[v]){ tarjan(v, u); low[u] = min(low[v], low[u]); } else if(Instack[v]){ low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]){ scc_clock++; do{ v = Stack[--top]; Instack[v] = false; Belong[v] = scc_clock; }while(u != v); } } void find(){ memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(Instack, false, sizeof(Instack)); memset(Belong, 0, sizeof(Belong)); dfs_clock = scc_clock = top = 0; for(int i = 1; i <= n; ++i){ if(!dfn[i]) tarjan(i, i); } } void suodian(){ for(int i = 1; i <= scc_clock; ++i) out[i] = 0; for(int i = 0; i < cnt; ++i){ int u = Belong[edge[i].u]; int v = Belong[edge[i].v]; if(u != v) out[u]++; } } void solve(){ int ans = 0; int temp = 0; int i; for(int i = 1; i <= scc_clock; ++i){ //printf("%d\n", out[i]); if(out[i] == 0){ temp = i; ans++; if(ans > 1){ printf("0\n"); return ; } } } int num = 0; for(int i = 1; i <= n; ++i){ if(Belong[i] == temp) num++; } printf("%d\n", num); } int main (){ while(scanf("%d%d", &n, &m) != EOF){ init(); getmap(); find(); suodian(); solve(); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 2186 -- Popular Cows【强连通分支 && Tarjan缩点】
原文地址:http://blog.csdn.net/hpuhjh/article/details/47782357