题目链接:http://poj.org/problem?id=2762
思路:tarjan进行缩点,得到一个有向无环图。要想形成弱联通的所有的点至少要连成一条,可能会有重边,也就是最多只能存在一个入度为零的和一个出度为零的点。如下图,黑色箭头必须,蓝色箭头可有可无。
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1005;
int n,m,e,head[N],dfn[N],low[N],index,cnt,belong[N],ind[N],out[N];
int stack[N],insta[N],top;
int hd[N];
struct node
{
int u,next;
}edge[6005];
int min(int a,int b)
{
if(a<b)
return a;
return b;
}
void init()
{
e=0;cnt=1;index=0;top=0;
memset(head,-1,sizeof(head));
memset(dfn,-1,sizeof(dfn));
memset(insta,0,sizeof(insta));
memset(ind,0,sizeof(ind));
memset(out,0,sizeof(out));
memset(hd,0,sizeof(hd));
}
void add(int a,int b)
{
edge[e].u=b;
edge[e].next=head[a];
head[a]=e++;
}
void Tarjan(int a)
{
int i,v;
dfn[a]=low[a]=cnt++;
stack[++top]=a;
insta[a]=1;
for(i=head[a];i!=-1;i=edge[i].next)
{
v=edge[i].u;
if(dfn[v]==-1)
{
Tarjan(v);
low[a]=min(low[a],low[v]);
}
else if(insta[v])
{
low[a]=min(low[a],dfn[v]);
}
}
if(dfn[a]==low[a])
{
index++;
do
{
v=stack[top--];
belong[v]=index;
insta[v]=0;
}
while(top!=0&&v!=a);
}
}
int main()
{
int i,j,cas,a,b,ans1,ans2;
//freopen("in.txt","r",stdin);
scanf("%d",&cas);
while(cas--)
{
init();
scanf("%d%d",&n,&m);
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
}
for(i=1;i<=n;i++)
if(dfn[i]==-1)
Tarjan(i);
for(i=1;i<=n;i++)
for(j=head[i];j!=-1;j=edge[j].next)
if(belong[i]!=belong[edge[j].u])
{
out[belong[i]]++;
ind[belong[edge[j].u]]++;
}
ans1=0;ans2=0;
for(i=1;i<=index;i++)
{
if(ind[i]==0)
ans1++;
if(out[i]==0)
ans2++;
}
if(ans1==1&&ans2==1)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}