http://poj.org/problem?id=2762
题意:给你n个房间,m条单向边,问你对于任意的x,y是否都有一条道路从x到y,或者从y到x。
思路:先用tarjan缩点,再用拓扑排序,如果发现去掉一个点之后有新增两个入度为0的点,则不能。
附上测试数据
4 4
1 2
2 3
3 4
2 4
Yes
4 3
1 2
2 3
2 4
No
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
#include <algorithm>
#define maxn 1005
using namespace std;
vector<int>edge[maxn];
vector<int>Edge[maxn];
int DFN[maxn],LOW[maxn],belong[maxn];
int Stack[maxn];
bool Instack[maxn];
int Index,cnt,top;
bool vis[maxn];
int in[maxn];
void Tarjan(int u)
{
int v;
DFN[u]=LOW[u]=++Index;
Stack[++top]=u;
Instack[u]=true;
for(int i=0;i<edge[u].size();i++)
{
v=edge[u][i];
if(DFN[v]==0)
{
Tarjan(v);
LOW[u]=min(LOW[v],LOW[u]);
}
else if(Instack[v])
LOW[u]=min(LOW[u],DFN[v]);
}
if(DFN[u]==LOW[u])
{
cnt++;
do
{
v=Stack[top--];
Instack[v]=false;
belong[v]=cnt;
}
while(u!=v);
}
}
bool topo()
{
queue<int>q;
memset(vis,false,sizeof(vis));
int ans=0;
for(int i=1;i<=cnt;i++)
{
if(in[i]==0)
{
q.push(i);
ans++;
// cout<<"i="<<i<<endl;
}
}
if(ans>1)return false;
while(!q.empty())
{
ans=0;
int cur=q.front();q.pop();
for(int i=0;i<Edge[cur].size();i++)
{
int v=Edge[cur][i];
in[v]--;
if(in[v]==0&&!vis[v])
{
ans++;
q.push(v);
vis[v]=true;
}
}
//cout<<cur<<" "<<ans<<endl;
if(ans>1)return false;
}
return true;
}
void init(int n)
{
Index=top=cnt=0;
memset(DFN,0,sizeof(DFN));
for(int i=1;i<=n;i++)
{
edge[i].clear();
Edge[i].clear();
}
}
int main()
{
int t,n,m;
cin>>t;
while(t--)
{
cin>>n>>m;
init(n);
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
}
for(int i=1;i<=n;i++)
if(DFN[i]==0)
Tarjan(i);
memset(in,0,sizeof(in));
for(int u=1;u<=n;u++)
{
for(int j=0;j<edge[u].size();j++)
{
int v=edge[u][j];
if(belong[u]!=belong[v])
{
// cout<<"from"<<belong[u]<<" to"<<belong[v]<<endl;
Edge[belong[u]].push_back(belong[v]);
in[belong[v]]++;
}
}
}
topo()?puts("Yes"):puts("No");
}
}