bzoj1051: [HAOI2006]受欢迎的牛(tarjan板子)
1051: [HAOI2006]受欢迎的牛
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6064 Solved: 3179
[Submit][Status][Discuss]
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
Source
Resolution
tarjan缩点板子题√
先对于整个图tarjan缩一次点
只需要判断出度为0的点即可,记录一下这个缩点之后的点里有几头牛
板子我都不会打,(我太弱啦!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #include<stack> #define N 1000001 using namespace std; inline int read() { int f=1,x=0;char ch=getchar(); while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch<='9'&&ch>='0') { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } return f*x; } stack<int> s; struct node { int w, v, next; }edge[100001*4]; int tot,head[N],size[N],son[N],ans,a[N],all[N],dfn[N],du[N],low[N],vis[N],sum,id[N]; void add(int u,int v) { edge[++tot].next=head[u]; edge[tot].v=v; head[u]=tot; } void tarjan(int x) { s.push(x); dfn[x]=low[x]=++tot; for(int i=head[x];i!=-1;i=edge[i].next) { int v=edge[i].v; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(!id[v])//id数组存放点缩点之后属于的新点 low[x]=min(low[x],dfn[v]); } if(dfn[x]==low[x]) { sum++;//缩点的新点下标 while(!s.empty()) { int num=s.top(); s.pop(); id[num]=sum; all[sum]++; if(x==num)break; } } return; } int cnt; int main() { memset(head,-1,sizeof(head)); int i; int n=read(),m=read(); for(i=1;i<=m;i++) {//cout<<1<<endl; int a=read(),b=read(); add(a,b);//cout<<1<<endl; } // cout<<1<<endl; tot=0; for(i=1;i<=n;i++) { if(!dfn[i])tarjan(i); } for(i=1;i<=n;i++) for(int j=head[i];j!=-1;j=edge[j].next) { int v=edge[j].v; if(id[i]!=id[v])du[id[i]]++;//计算出度 } for(i=1;i<=sum;i++) { if(du[i]==0) { cnt++; ans=i; } } if(cnt!=1) cout<<0; else cout<<all[ans]; }
就让我永远不在这里写下什么有意义的话——by 吉林神犇 alone_wolf