您的位置:首页 > 其它

bzoj1051: [HAOI2006]受欢迎的牛

2017-03-08 21:29 363 查看
传送门

tarjan大法好。

先用tarjan对原图缩点,再在新图上跑一边拓扑排序就行了。

新图上记忆化搜索也行。

#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<iostream>
#include<algorithm>
#define nn 100005
using namespace std;
int to[nn],to2[nn],he[nn],he2[nn],ne[nn],ne2[nn];
int low[nn],dfn[nn],in[nn],vis[nn],s[nn],be[nn],bnum[nn],f[nn];
int n,m,p,q,ti,cnt,top,num,ans,edg;
void tar(int x){
dfn[x]=low[x]=++ti;
in[x]=vis[x]=1;
s[++top]=x;
for (int i=he[x];i;i=ne[i]){
if (!vis[to[i]]){
tar(to[i]);
low[x]=min(low[to[i]],low[x]);
}
if (in[to[i]]) low[x]=min(low[x],dfn[to[i]]);
}
if (dfn[x]==low[x]){
cnt++;
for (;s[top+1]!=x;top--){
be[s[top]]=cnt;
in[s[top]]=0;
bnum[cnt]++;
}
}
}
void rebuild(){
for (int i=1;i<=n;i++)
for (int j=he[i];j;j=ne[j])
if (be[i]!=be[to[j]]){
to2[++edg]=be[to[j]];
ne2[edg]=he2[be[i]];
he2[be[i]]=edg;
}
}
void work(){
int tot=0;
for (int i=1;i<=cnt;i++){
memset(f,0,sizeof(f));
int fl=0;
for (int j=he2[i];j;j=ne2[j])
if (!f[to2[j]]){
f[to2[j]]=1;
fl=1;
}
if (!fl){
tot++;
ans=bnum[i];
}
if (tot>1){
ans=0;
break;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d",&p,&q);
to[i]=q;
ne[i]=he[p];
he[p]=i;
}
for (int i=1;i<=n;i++)
if (!vis[i]) tar(i);
rebuild();
work();
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: