正题
题目链接
大意
有n头奶牛,奶牛们会认为有些奶牛很受欢迎,受欢迎会互相传递,如:如果A认为B很受欢迎,而B认为C受欢迎,那么A也会认为C是受欢迎的。然后求每一个奶牛都认为受欢迎的奶牛数量。
解题思路
先用tarjan算法算一遍联通分量,然后如果该联通分量出度为0且是唯一一个为0的,那么这个强联通分量里就是受每个奶牛欢迎的。
讲解一下原理:
首先我们假设这道题有解,那么我们将每一个强联通分量看做一个整体,然后如果该整体有出度那么说明这不是最受欢迎的(因为如果受到出度链接的那个整体欢迎的话那么就应该是一个联通分量里的)。如果有两个出度为0那么这两个整体就不会互相喜欢,就无解。
代码
#include<cstdio>
#include<stack>
using namespace std;
stack<int> Stack;
struct line{int h,t,next;
};
int n,m,dfn[10001],low[10001],stn,ls[10001],ltn,lt[10001];
int ltm[10001],wr[10001],s1,ans;
bool instack[10001];
line a[50001];
void tarjan(int x)
{dfn[x]=low[x]=++stn;instack[x]=true;Stack.push(x);//入栈int y;for (int q=ls[x];q;q=a[q].next)//枚举连接到{y=a[q].t;if (!dfn[y])//如果没用计算{tarjan(y);//计算low[x]=min(low[x],low[y]);//更新low值}else if (instack[y] && low[x]>dfn[y])low[x]=dfn[y];}if (dfn[x]==low[x]){ltn++;while (Stack.size()>0){y=Stack.top();Stack.pop();ltm[ltn]++;lt[y]=ltn;if (y==x) break;}//归入同一个强连通分量}
}
int main()
{scanf("%d%d",&n,&m);for (int i=1;i<=m;i++){scanf("%d%d",&a[i].h,&a[i].t);a[i].next=ls[a[i].h];ls[a[i].h]=i;}for (int i=1;i<=n;i++)if (dfn[i]==0) tarjan(i);//跑一遍for (int i=1;i<=m;i++)if (lt[a[i].t]!=lt[a[i].h]){wr[lt[a[i].h]]++;}//计算每个强连通的出度for (int i=1;i<=ltn;i++)if (!wr[i]){ans=i;s1++;//计算出度为0的数量}if (s1==1) printf("%d",ltm[ans]);else printf("0");
}