codevs 2822 爱在心中

第一问的裸的tarjan很简单,关键是第二问。

我们考虑将整张图缩点,那么出度为0的点(块)可能满足条件。

重点来了:如果存在两个以上的出度为0的块,则不满足条件(这两块没有任何关系)

加之此题数据水。。。。。

#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxv 50005
#define maxe 50005
using namespace std;
int n,m,low[maxv],dfn[maxv],g[maxv],nume=0,times=0,x,y,cnt=0;
int father[maxv],ans=0,inq[505],map[505][505],regis[505];
bool ins[maxv],vis[maxv];
stack <int> s;
struct edge
{
int u,v,nxt;
}e[maxe];
void addedge(int u,int v)
{
e[++nume].u=u;
e[nume].v=v;
e[nume].nxt=g[u];
g[u]=nume;
}
void tarjan(int u)
{
++times;
low[u]=times;
dfn[u]=times;
s.push(u);
vis[u]=true;
ins[u]=true;
for (int i=g[u];i;i=e[i].nxt)
{
int v=e[i].v;
if (vis[v]==false)
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if (ins[v]==true)
low[u]=min(low[u],dfn[v]);
}
if (low[u]==dfn[u])
{
int vtx;
cnt++;int cc=0;
do
{
vtx=s.top();
s.pop();
ins[vtx]=false;
father[vtx]=cnt;
map[cnt][++cc]=vtx;
}
while (vtx!=u);
if (cc>1) ans++;
}
}
int main()
{
memset(g,0,sizeof(g));
memset(vis,false,sizeof(vis));
memset(ins,false,sizeof(ins));
memset(inq,0,sizeof(inq));
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
addedge(x,y);
}
for (int i=1;i<=n;i++)
if (vis[i]==false)
tarjan(i);
printf("%d ",ans);
for (int i=1;i<=nume+1;i++)
{
if (father[e[i].u]!=father[e[i].v])
inq[father[e[i].u]]++;
}
int flag=0,x;
for (int i=1;i<=cnt;i++)
{
if (inq[i]==0)
{
flag++;
x=1;
while (map[i][x]!=0)
{
regis[x]=map[i][x];
x++;
}
}
}
if ((flag==0) || (flag==2) || (x<=2)) printf("-1 ");
else
{
sort(regis+1,regis+x);
for (int i=1;i<=x-1;i++)
printf("%d ",regis[i]);
}
return 0;
}

原文地址:https://www.cnblogs.com/ziliuziliu/p/5080672.html