bzoj1051受欢迎的牛(Tarjan)
1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4776 Solved: 2542
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这
种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头
牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可
能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1
HINT
100%的数据N<=10000,M<=50000
/*这是一个缩点Tarjan求环的裸题 */ #include<iostream> #include <cstdio> #include <cstring> using namespace std; const int Maxn = 10005; const int Maxm = 100005; struct node { int to,next; } edge[Maxm]; int n,m,head[Maxn],dfn[Maxn],low[Maxn],stack1[Maxn],num[Maxn],du[Maxn],vis[Maxn],cnt,tt,top,cut; void init() { memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); memset(du,0,sizeof(du)); } void addedge(int u,int v) { edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; cnt++; } void Tarjan(int u,int fa) { dfn[u]=tt; low[u]=tt; tt++; vis[u]=1; stack1[top]=u; top++; for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].to; if(!vis[v]) { Tarjan(v,u); low[u]=min(low[u],low[v]); } else if(vis[v]) { low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]) { cut++; while(top>0&&stack1[top]!=u) { top--; vis[stack1[top]]=2; num[stack1[top]]=cut; } } } int main() { int u,v; while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=0; i<m; i++) { scanf("%d%d",&u,&v); addedge(u,v); } for(int i=1; i<=n; i++) { if(!vis[i]) { Tarjan(i,0); } } for(int i=1; i<=n; i++) { for(int j=head[i]; j!=-1; j=edge[j].next) { if(num[i]!=num[edge[j].to]) { du[num[i]]++; } } } int sum=0,x; for(int i=1; i<=cut; i++) { if(!du[i]) { sum++; x=i; } } if(sum==1) { sum=0; for(int i=1; i<=n; i++) { if(num[i]==x) { sum++; } } printf("%d\n",sum); } } return 0; }
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=10005,M=50005; int n=0,m=0; int head[N],to[M],next[M],edge=0; int dfn[N],inS[N],idx=1,low[N]; int stk[N],top=0; int comp[N],n2=0,cnt[N]; int in[N]; int head2[N],to2[M],next2[M],edge2=0; int q[N*233],front=0,back=0,vis[N]; inline void addEdge(int u,int v) { to[edge]=v,next[edge]=head[u],head[u]=edge++; } void tarjan(int x) { dfn[x]=low[x]=idx++; stk[top++]=x; inS[x]=1; for (int e=head[x];~e;e=next[e]) { int& v=to[e]; if (!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if (inS[x]) low[x]=min(low[x],dfn[v]); } if (dfn[x]==low[x]) { ++n2; int u=0; do { u=stk[--top]; comp[u]=n2; inS[u]=0; ++cnt[n2]; } while (u!=x); } } inline void addEdge2(int u,int v) { ++in[v]; to2[edge2]=v,next2[edge2]=head2[u],head2[u]=edge2++; } inline void build() { for (int i=1;i<=n;++i) for (int e=head[i];~e;e=next[e]) { int &u=comp[i],&v=comp[to[e]]; if (u!=v) addEdge2(v,u); } } inline int bfs(int s) { front=back=0; memset(vis,0,sizeof(vis)); q[back++]=s; vis[s]=1; while (front<back) { int x=q[front++]; for (int e=head2[x];~e;e=next2[e]) { int& v=to2[e]; if (!vis[v]) { q[back++]=v; vis[v]=1; } } } for (int i=1;i<=n2;++i) if (!vis[i]) return 0; return 1; } int main(void) { memset(head,-1,sizeof(head)); scanf("%d %d",&n,&m); while (m--) { int u=0,v=0; scanf("%d %d",&u,&v); addEdge(u,v); } for (int i=1;i<=n;++i) if (!dfn[i]) tarjan(i); //建缩点以后的反图 就所有入度为0的点bfs memset(head2,-1,sizeof(head2)); build(); int ans=0; for (int i=1;i<=n2;++i) if (!in[i]) if (bfs(i)) ans+=cnt[i]; printf("%d\n",ans); return 0; }
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。