poj 2186 Popular Cows 有向圖的連通性 tarjan + 縮點


題目描述:

牛之間有支持關系,這種關系可以傳遞。A 支持B,B支持C,則A支持C。給出一系列關系,求出有幾頭牛獲得了其他所有牛的支持。

地址:http://poj.org/problem?id=2186

分析:

這道題說來慚愧,由於第一次寫tarjan,第一次寫縮點,在不是很了解過程的情況下看了大牛的代碼,看后明白了,自己寫了一遍,寫出來的跟大牛的特別像!如果發現哪位大牛的代碼跟本代碼類似,請不要驚慌,這段代碼的確是看了他們的寫出來的!

以上閑扯。思路:將所有強連通分量縮點,然后對這些點找出出度為0的點,如果這樣的點超過兩個,則題目沒有答案;如果只有一個,則輸出這個店所包含的點數,即有多少點縮點后得到的這個點。(有點羅嗦,見諒)

分析很簡單,但是第一次寫代碼卻花了很長時間,下面代碼

#include<stdio.h>
#include<string.h>
#define max_n 10005
#define max_e 50005

int stack[max_n], top; //
bool visited[max_n]; //該點是否在棧中
int low[max_n]; //點的low值
int dfn[max_n], times; //點的dfn值 time從1開始
//////////////////
int belong[max_n]; //縮點后點屬於某個node
int Node_num[max_n], type;//縮點后node含點的個數 type從1開始
int Node_out[max_n]; //縮點后node的出度
///////////////////
int head[max_n], s_edge;//鄰接表頭 s_edge從1開始
struct E{
int to, next;
}edge[max_e]; //鄰接表
void init(){
top = 0;
memset(visited, 0, sizeof(visited));
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn)); times = 0;
memset(belong, 0, sizeof(belong));
memset(Node_num, 0, sizeof(Node_num)); type = 0;
memset(Node_out, 0, sizeof(Node_out));
memset(head, 0, sizeof(head)); s_edge = 0;
memset(edge, 0, sizeof(edge));
}

void add_in_edge(int u, int v){
s_edge++;
edge[s_edge].to = v;
edge[s_edge].next = head[u];
head[u] = s_edge;
}
int min(int a, int b){
if(a<b) return a;
else return b;
}
//tarjan是用dfs實現的一深搜棵樹
void tarjan(int u){ //low值為u或u的子樹能夠追溯到得最早的棧中節點的次序號
stack[top++] = u;
visited[u] = true;
dfn[u] = ++times; //記錄點u出現的記錄,並放在棧中
low[u] = times;
int e, v;
for(e=head[u]; e; e = edge[e].next){//如果是葉子節點,head[u]=0,edge[e].next=0;
     v = edge[e].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(visited[v])
low[u] = min(low[u], dfn[v]);
}
int j;
if(dfn[u] == low[u]){
type++;
while(j = stack[--top]){//退棧
visited[j] = false;
belong[j] = type;//為縮點做准備
      Node_num[type]++;
if(j == u)
break;
}
}
}

int main(){
int N, M, A, B;
int i;
init();
scanf("%d %d",&N, &M);
for(i=0; i<M; i++){
scanf("%d %d",&A, &B);
add_in_edge(A, B);
}
for(i=1; i<=N; i++)
if(!dfn[i])
tarjan(i);
int u, e, v, num=0;
for(u=1; u<=N; u++){//縮點
     for(e=head[u]; e; e=edge[e].next){
v = edge[e].to;
if(belong[v] != belong[u])
Node_out[belong[u]]++;
}
}
int ans;
for(i=1; i<=type; i++){
if(Node_out[i] == 0){
ans = Node_num[i];
num++;
}
}
if(num >1)
printf("0\n");
else printf("%d\n",ans);
return 0;
}




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com