| 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