POJ2762 Going from u to v or from v to u?(强联通分量)

来源:互联网 发布:泉立方是什么 知乎 编辑:程序博客网 时间:2024/04/27 16:21

题目大意:有n个点的有向图,对于其中任意两点u,v是否都能使u能走到v或者v能走到u(注意是或者!!!),如果是输出Yes,否则输出No。


思路:裸的强联通。学了几天没写强联通的题,手又生了大哭。对于图中的每个环,它们之间都能够相互到达,所以把它们缩成一个点(联通块)。然后判断缩点后的图是否为一条单向的链,如果是,那么条件肯定成立。否则不成立。

#include<cstdio>#include<cstring>#define MAXN 1005#define Min(a,b) a<b?a:busing namespace std;struct T{int v;int next;}edge[6005];int cnt;int head[MAXN];void add_edge(int u,int v){edge[cnt].v = v;edge[cnt].next = head[u];head[u] = cnt++;}int n,m;int dcnt;int low[MAXN],dfn[MAXN];int stack[MAXN],tot;bool instack[MAXN];int cut_e,belong[MAXN];int in[MAXN];bool arr[MAXN][MAXN],vis[MAXN];void dfs(int u){low[u] = dfn[u] = ++dcnt;stack[++tot] = u;instack[u] = true;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;if(!dfn[v]){dfs(v);low[u] = Min(low[u],low[v]);}else if(instack[v]){low[u] = Min(low[u],dfn[v]);}}if(low[u] == dfn[u])//找到一个联通块{++cut_e;do{belong[stack[tot]] = cut_e;instack[stack[tot]] = false;tot--;}while(stack[tot+1] != u);}}int ans;void count(int u){vis[u] = 1;++ans;for(int i = 1; i <= cut_e; i++){if(arr[u][i]&&!vis[i])//打成!vis[u],立碑纪念{count(i);return;}}}int main(){int T;scanf("%d",&T);while(T--){memset(edge,0,sizeof edge);memset(low,0,sizeof low);memset(dfn,0,sizeof dfn);memset(head,-1,sizeof head);memset(belong,0,sizeof belong);memset(in,0,sizeof in);memset(vis,0,sizeof vis);memset(arr,0,sizeof arr);cnt = dcnt = 0;tot = 0;cut_e = 0;scanf("%d%d",&n,&m);for(int i = 1; i <= m; i++){int a,b;scanf("%d%d",&a,&b);add_edge(a,b);}for(int i = 1; i <= n; i++)if(!dfn[i])dfs(i);for(int u = 1; u <= n; u++)//缩点,构建新图{for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].v;if(belong[u] != belong[v]&&!arr[belong[u]][belong[v]])//打成!arr[u][v],立碑纪念{arr[belong[u]][belong[v]] = 1;//新图连边in[belong[v]]++;//入度加1}}}ans = 0;for(int i = 1; i <= cut_e; i++)//判断是否为一条链,也就是从一个入度为0的点走看是否能走完所有联通块{if(in[i] == 0){count(i);break;}}if(ans == cut_e) printf("Yes\n");else printf("No\n");}}


0 0
原创粉丝点击