http://poj.org/problem?id=2762
题目给出n个点m条单向边,问是否存在取任意两点x,y,使得可以x->y或y->x,其实就是求弱连通分量....
方法:缩点+拓扑。因为环内各点肯定可以任意到达,缩完点后就可能变成树或森林,当树是一条链的时候才存在弱连通分量,拓扑一下就ok...
一开始看不到The cave has n rooms, andone-way corridors connecting some rooms.单向边!!!以为是无向边,并且每条边只能走一次,如果这样的话,就跟zoj3583一样,变了求简单路径
#define N 1004
int n;
bool g[N][N];
bool vis[N];
bool inStack[N];
int out[N],in[N];
int belong[N];
int low[N],dfn[N];
stack<int> st;
int t;//the number of 强连通分量
int step;
int min(int a,int b){
return a>b?b:a;
}
int max(int a,int b){
return a>b?a:b;
}
void init(){
t = 0;
memset(g,0,sizeof(g));
memset(vis,0,sizeof(vis));
memset(belong,0,sizeof(belong));
memset(inStack,0,sizeof(inStack));
while(!st.empty())st.pop();
}
void tarjan(int u){
int i,j,k;
step++;
low[u]=step;
dfn[u]=step;
vis[u]=1;
inStack[u]=1;
st.push(u);
for(i=1;i<=n;i++)
{
if(g[u][i])
{
if(!vis[i])
{
tarjan(i);
low[u]=min(low[u],low[i]);
}
else
if(inStack[i])
low[u]=min(low[u],dfn[i]);
}
}
if(low[u]==dfn[u])
{
t++;
while(1)
{
int a=st.top();
st.pop();
belong[a]=t;
inStack[a]=0;
if(a==u)break;
}
}
}
int du[N];
int gg[N][N];
bool vv[N];
bool topo(){
int i,j;
queue<int> qq;
for(i=1;i<=t;i++){
vv[i] = 0;
if(!du[i]){
qq.push(i);
vv[i] = 1;
}
}
int sz = qq.size();
if(sz!=1)return false;
while(!qq.empty()){
int u = qq.front();
qq.pop();
int cnt = 0;
for(i=1;i<=t;i++){
if(!vv[i] && gg[u][i]){
du[i]--;
if(du[i]==0){
cnt++;
qq.push(i);
vv[i] = 1;
}if(cnt>=2)return false;
}
}
}
return true;
}
int main(){
int ca;
scanf("%d",&ca);
while(ca--){
int m;
scanf("%d%d",&n,&m);
int i,j;
init();
while(m--){
int x,y;
scanf("%d%d",&x,&y);
g[x][y] = 1;
}
for(i=1;i<=n;i++){
if(!vis[i])tarjan(i);
}
for(i=0;i<=t;i++)du[i] = 0;
memset(gg,0,sizeof(gg));
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(g[i][j]){
int a = belong[i];
int b = belong[j];
if(a!=b){
du[b]++;
gg[a][b] = 1;
}
}
}
}
if(topo())puts("Yes");
else puts("No");
}
return 0;
}