题目描述:
牛之间有支持关系,这种关系可以传递。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;
}