题意:有n头牛,若A认为B是受欢迎的,那么B的人气+1,认为某头牛受欢迎是可以传递的。最后问有多少头牛的人气是n-1。
思路:先用tarjan求个强连通分量,可以得到一个DAG,则同一个强连通分量中的点相互认为对方受欢迎。然后选择所有入度为0的点,从这一点开始遍历,计算其子节点的人气,需要注意的是由于有横叉边,所以到某个节点直接从这个点往下搜是不对的,一个简单的方法就是计算到达这个点的次数,如果等于该点的入度,那么就往下搜,如果不等,就先“等”,一直到下次访问这个点。这题刚开始一看感觉挺水的,但是wa了好几次,刚开始是被题意坑了,后来又没有考虑到横叉边,真是桑心……
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=10000+10; const int maxm=50000+10; struct Edge { int v,next; }; Edge edges[maxm<<1],ee[maxm<<1]; int head[maxn],hh[maxn],nEdge,ne; int pre[maxn],sccno[maxn],dfs_clock,scc_cnt; int degree[maxn],d2[maxn],val[maxn],sup[maxn],maxsup; stack<int>S; void AddEdge(int u,int v) { nEdge++; edges[nEdge].v=v; edges[nEdge].next=head[u]; head[u]=nEdge; } void addedge(int u,int v) { ne++; ee[ne].v=v; ee[ne].next=hh[u]; hh[u]=ne; } void Init() { memset(head,0xff,sizeof(head)); memset(hh,0xff,sizeof(hh)); memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); memset(degree,0,sizeof(degree)); memset(sup,0,sizeof(sup)); memset(val,0,sizeof(val)); memset(d2,0,sizeof(d2)); nEdge=ne=-1; } int tarjan(int u) { int lowu=pre[u]=++dfs_clock; S.push(u); for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].v; if(!pre[v]) { int lowv=tarjan(v); lowu=min(lowu,lowv); } else if(!sccno[v]) lowu=min(lowu,pre[v]); } if(lowu==pre[u]) { scc_cnt++; while(true) { int x=S.top();S.pop(); sccno[x]=scc_cnt; if(x==u) break; } } return lowu; } void find_scc(int n) { dfs_clock=scc_cnt=0; for(int i=1;i<=n;++i) if(!pre[i]) tarjan(i); } void dfs(int u) { if(val[u]>1) sup[u]+=(val[u]-1); maxsup=max(maxsup,sup[u]); for(int k=hh[u];k!=-1;k=ee[k].next) { int v=ee[k].v; sup[v]+=sup[u]+1; d2[v]++; if(d2[v]==degree[v]) dfs(v); } } void solve(int n) { int v; for(int u=1;u<=n;++u) { val[sccno[u]]++; for(int k=head[u];k!=-1;k=edges[k].next) { v=edges[k].v; if(sccno[u]!=sccno[v]) { addedge(sccno[u],sccno[v]); degree[sccno[v]]++; } } } maxsup=0; for(int i=1;i<=scc_cnt;++i) if(!degree[i]) dfs(i); if(maxsup!=n-1) { printf("0\n"); return; } int cnt=0; for(int i=1;i<=n;++i) { if(sup[sccno[i]]==maxsup) cnt++; } printf("%d\n",cnt); } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); int n,m; scanf("%d%d",&n,&m); Init(); int u,v; for(int i=0;i<m;++i) { scanf("%d%d",&u,&v); AddEdge(u,v); } find_scc(n); solve(n); return 0; }