poj2762 强连通+拓扑序

题意:有 n 个房间,不同房间之间有单向通道,问是否任意两个房间 A 、B 都可以从 A 到 B 或从 B 到 A(有一条有就可以)。

在这题中,如果一些点是在同一个强连通分量中,那么这些点肯定能够相互到达,并且如果其他的点到达这里的任意一点,也就可以到达强连通分量中的所有点,所以首先需要对这题进行缩点。缩点之后图中就不存在环了,这时需要所有点间都至少有一条路,所以其实剩下了一条长链,并且是单向的,如果有双向的边就会被缩点,如果是数型图的话那么一个节点的多个子树就不能互相到达,所以一定是一条单向的长链,因此只要拓扑序判断就行,也可以对于这个图判段是否只有一点入度为1,一点出度为1,剩余点出入度都为1就行。

 #include<stdio.h>
#include<string.h>
#include<stack>
#include<queue>
using namespace std; const int maxn=;
const int maxm=; int head[][maxn],point[][maxm],nxt[][maxm],size[];
int n,t,scccnt;
int id[maxn],stx[maxn],low[maxn],scc[maxn];
stack<int>S; void init(){
memset(head,-,sizeof(head));
size[]=size[]=;
memset(id,,sizeof(head));
} void add(int a,int b,int c=){
point[c][size[c]]=b;
nxt[c][size[c]]=head[c][a];
head[c][a]=size[c]++;
if(c)id[b]++;
} void dfs(int s){
stx[s]=low[s]=++t;
S.push(s);
for(int i=head[][s];~i;i=nxt[][i]){
int j=point[][i];
if(!stx[j]){
dfs(j);
low[s]=min(low[s],low[j]);
}
else if(!scc[j]){
low[s]=min(low[s],stx[j]);
}
}
if(low[s]==stx[s]){
scccnt++;
while(){
int u=S.top();S.pop();
scc[u]=scccnt;
if(s==u)break;
}
}
} void setscc(){
memset(stx,,sizeof(stx));
memset(scc,,sizeof(scc));
t=;
scccnt=;
for(int i=;i<=n;++i)if(!stx[i])dfs(i);
for(int i=;i<=n;++i){
for(int j=head[][i];~j;j=nxt[][j]){
int k=point[][j];
if(scc[i]!=scc[k]){
add(scc[i],scc[k],);
}
}
}
} bool topo(){
queue<int>q;
int cnt=;
for(int i=;i<=scccnt;++i)if(!id[i])q.push(i);
while(!q.empty()){
int u=q.front();
q.pop();
if(!q.empty())return ;
cnt++;
for(int i=head[][u];~i;i=nxt[][i]){
int j=point[][i];
id[j]--;
if(!id[j])q.push(j);
}
}
if(cnt==scccnt)return ;
return ;
} int main(){
int T;
scanf("%d",&T);
while(T--){
int m;
scanf("%d%d",&n,&m);
init();
while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
setscc();
if(topo())printf("Yes\n");
else printf("No\n");
}
return ;
}
上一篇:BZOJ-4010 菜肴制作 贪心+堆+(拓扑图拓扑序)


下一篇:poj3553 拓扑序+排序贪心