【poj2186】 Popular Cows
http://poj.org/problem?id=2186 (题目链接)
题意
给出一个n个点m条边的有向图,求其中没有出度强连通分量所包含的点有几个
Solution
其实这道题的题解已经在“题意”中给出了= =,先Tarjan跑出强连通分量,之后模拟给缩点后的图连边(其实并不用真的连边),来统计缩点后每个节点的出度。输出出度为0的强连通分量所包含的点即可,若有多个强连通分量出度为0,输出0(不要问我为什么,有时候事情就是这么不讲道理)。
代码
// poj2186 #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<set> #define MOD 1000000007 #define inf 2147483640 #define LL long long #define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout); using namespace std; inline LL getint() { LL x=0,f=1;char ch=getchar(); while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();} return x*f; } const int maxn=50010; struct edge {int to,next;}e[maxn<<2]; int f[maxn],dfn[maxn],low[maxn],head[maxn],s[maxn],pos[maxn],cnts[maxn]; int ind,cnt,n,m,top,tot; void insert(int u,int v) { e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt; } void Tarjan(int u) { dfn[u]=low[u]=++ind; s[++top]=u; f[u]=1; for (int i=head[u];i;i=e[i].next) { if (!dfn[e[i].to]) { Tarjan(e[i].to); low[u]=min(low[u],low[e[i].to]); } else if (f[e[i].to]) low[u]=min(low[u],dfn[e[i].to]); } if (dfn[u]==low[u]) { tot++;int j; do { j=s[top--]; pos[j]=tot; cnts[tot]++; f[j]=0; }while (j!=u); } } int main() { while (scanf("%d%d",&n,&m)!=EOF) { top=0;cnt=0;ind=0;tot=0; for (int i=1;i<=n;i++) dfn[i]=low[i]=head[i]=cnts[i]=pos[i]=0; for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); insert(x,y); } for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i); cnt=0;for (int i=1;i<=n;i++) f[i]=0; for (int i=1;i<=n;i++) for (int j=head[i];j;j=e[j].next) if (pos[i]!=pos[e[j].to]) f[pos[i]]++; int ans=0; for (int i=1;i<=tot;i++) if (!f[i]) ans++; if (ans>1) printf("0\n"); else { ans=0; for (int i=1;i<=tot;i++) if (!f[i]) ans+=cnts[i]; printf("%d\n",ans); } } return 0; }
This passage is made by MashiroSky.