Description
Input
Output
Sample Input
1 3 3 1 2 2 3 3 1
Sample Output
Yes
题意:给出的图是否可以随意的指定某两点:从u可以到v 或者从v到u。这里注意的是题目给出的是or!!!!不是双向连通的,而单连通!
思路:那么根据题目意思,就可以用Tarjan算法缩点后,重新建图,然后对新图进行拓扑排序,然后拓扑排序后的点与新图所有的结点总数相同,就说明是单连通的,反之……
不过有剪枝:就是如果出度为0的点有多个,那么肯定不能从u到v,或者从v到u,因为出度为0,所以就没有边连接u和v了;如果新建的图只有一个结点,那么直接是对的。
这题也是WA了好多发,昨天下午做到CF开始都没对,代码都已经早就写好了,改了5个小时都没对,后面晚上回来改也不对,今天做了H题,然后也是一直错,后面单步调试才发现在Tarjan中把min写成了max,靠!!!!!!!!!!!!!!!!!!!!!!细节决定成败啊!!!!!!!!!!做了整整两天了!!!!!
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <list>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define PI acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))
#define sca(a) scanf("%d",&a)
#define pri(a) printf("%d\n",a)
#define MM 10002
#define MN 1005
#define INF 168430090
using namespace std;
typedef long long ll;
int n,m,cnt,tem,Count,DFN[MN],LOW[MN],id[MN],vis[MN],suo[MN],q2[MN],Map[MN][MN];
stack<int>p;
vector<int>q[MN],q1[MN];
void tarjan(int u)
{
int j,v;
DFN[u]=LOW[u]=++cnt;
vis[u]=1; q2[++tem]=u;
for(j=0;j<q[u].size();j++)
{
v=q[u][j];
if(!DFN[v])
{
tarjan(v);
LOW[u]=min(LOW[u],LOW[v]); //和H题一样也是把min写成max,所以一直错都不知道,H题的Tarjan算法是从这里拿过去的,所以那题改过来了才知道这题也是这里错,改过来再提交直接AC,唉……昨晚搞到1点都不知道是这里错,大意了!
}
else if(vis[v]&&DFN[v]<LOW[u])
LOW[u]=DFN[v];
}
if(DFN[u]==LOW[u])
{
Count++;
do
{
v=q2[tem--];
vis[v]=0;
suo[v]=Count;
}while(v!=u);
}
}
void solve()
{
Count=cnt=tem=0;
mem(DFN,0);
for(int i=1;i<=n;i++)
if(!DFN[i]) tarjan(i);
}
int topsort()
{
if(Count==1||n==1) return 1; //如果新建的图只有一个结点,或者原图只有一条边,那肯定对啦
int i,v,u,sum=0;
for(i=1;i<=Count;i++)
if(!id[i]) p.push(i);
while(!p.empty())
{
if(p.size()>1) return 0; //出度超过2个结点肯定不对
u=p.top(); p.pop(); sum++;
for(v=0;v<q1[u].size();v++)
if(--id[q1[u][v]]==0) p.push(q1[u][v]);
}
if(sum!=Count) return 0;
return 1;
}
void suodian()
{
for(int i=1;i<=n;i++)
for(int j=0;j<q[i].size();j++)
if(suo[q[i][j]]!=suo[i]&&!Map[suo[q[i][j]]][suo[i]])
{
id[suo[q[i][j]]]++;
q1[suo[i]].push_back(suo[q[i][j]]);
Map[suo[q[i][j]]][suo[i]]=1;
}
}
void init()
{
for(int i=0;i<=n;i++)
{
q[i].clear();
q1[i].clear();
}
while(!p.empty()) p.pop();
mem(vis,0); mem(suo,0); mem(id,0); mem(Map,0);
}
int main()
{
int t,u,v;
sca(t);
while(t--)
{
init(); //多case需要初始化
scanf("%d%d",&n,&m);
while(m--)
{
scanf("%d%d",&u,&v);
q[u].push_back(v);
}
solve();
suodian();
if(topsort()) puts("Yes");
else puts("No");
}
return 0;
}CUGB图论专场2:G - Going from u to v or from v to u?单连通判断(Tarjan+Topsort)
原文:http://blog.csdn.net/u011466175/article/details/19483461