POJ 2762【强联通缩点】【拓扑排序】Going from u to v or from v to u?
来源:互联网 发布:卫生网络答题 编辑:程序博客网 时间:2024/05/16 05:46
题目大意是,判断一个有向图中所有的任意两点x,y,是否满足,从x可以走到y 或者 从y可以走到x
很显然,同一个SCC中的所有点一定满足这个条件,当同一个SCC中的所有点要么同时选要么同时不选的时候,就可以缩点了。缩点的方法就是给每个点加一个强联通分量编号(染色),然后tarjan结束后考察每一条边,若某条边的两头不是同一个颜色,就加一条新边。
缩点后的图一定是一个DAG(有向无环图),在这张新图上可以得到一个结论:若满足题目要求的条件,这个新图是不能有分叉的,因为一旦有了分叉,就会有叶节点,而叶节点是无法走到比其本身更深的点的,同样一个比叶节点更深的点也无法走回叶节点(图是有向的)
现在求的就是这个新图的最长链(如果判断出有分叉直接返回0),如果最长链等于新图点数(因为有可能会出现孤立的点),那么这张图便是可行的。
PS:可能输入给的不只有一个图,所以要加点东西:
for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i);
#include <iostream>#include <cstdio>#include <algorithm>#include <stack>#include <queue>#include <cstring>using namespace std;const int maxn = 6010;#define debug(x) cerr << #x << "=" << x << endl;#define mmm(x) memset(x,0,sizeof(x));int t,n,m,last[maxn],tot,l,dfn[maxn],low[maxn],color[maxn],sccnum;int tot_new,last_new[maxn],n_new,chain,cou;int id[maxn], od[maxn];bool ans, flg[maxn];stack <int> s;struct Edge{ int u,v,to; Edge(){} Edge(int u, int v, int to): u(u), v(v), to(to) {}}e[maxn];inline void addedge(int u, int v) { e[++tot] = Edge(u,v,last[u]); last[u] = tot;}void tarjan(int x) { dfn[x] = low[x] = ++cou; s.push(x); flg[x] = true; for(int i=last[x]; i; i=e[i].to) { if(!dfn[e[i].v]) { tarjan(e[i].v); if(low[e[i].v] < low[x]) low[x] = low[e[i].v]; } else if(dfn[e[i].v] < low[x] && flg[e[i].v]){ low[x] = dfn[e[i].v]; } } if(dfn[x]==low[x]) { int fr,num; sccnum++; //新图中的点数 do { fr = s.top(); s.pop(); flg[fr] = 0;//出栈了 num++; color[fr] = sccnum; }while(fr != x); }}struct Edge_new{ int u,v,to; Edge_new(){} Edge_new(int u, int v, int to): u(u), v(v), to(to) {}}e_new[maxn];inline void addedge_new(int u, int v) { e_new[++tot_new] = Edge_new(u,v,last_new[u]); last_new[u] = tot_new;} queue <int> q;bool topo() { for(int i=1; i<=sccnum; i++) { if(id[i] == 0) q.push(i); } while(!q.empty()) { int u = q.front(); q.pop(); if(!q.empty()) return false; //如果是单链,队列中一定是进一个出一个,如果队列中同时存在多个元素就说明有图分叉 for(int i=last_new[u]; i; i=e_new[i].to) { int v = e_new[i].v; id[v]--; if(!id[v]) q.push(v); } } return true;}bool solve() { for(int i=1; i<=tot; i++) { int u = e[i].u, v = e[i].v; if(color[u] != color[v]) { addedge_new(color[u],color[v]); od[color[u]]++; id[color[v]]++; } } if(topo()) return true; else return false;}int main() { scanf("%d",&t); while(t--) { mmm(dfn);mmm(low);mmm(color);mmm(last);mmm(flg); mmm(last_new);mmm(e);mmm(e_new);mmm(id);mmm(od); tot = 0;cou = sccnum = tot_new = chain = 0; while(!s.empty()) s.pop(); while(!q.empty()) q.pop(); ans = 0; scanf("%d %d", &n, &m); for(int i=1; i<=m; i++) { int u, v; scanf("%d %d", &u, &v); addedge(u,v); } for(int i=1; i<=n; i++) { if(!dfn[i]) tarjan(i); } if(solve()) printf("Yes\n"); else printf("No\n"); } return 0;}
阅读全文
0 0
- POJ 2762【强联通缩点】【拓扑排序】Going from u to v or from v to u?
- POJ 2762 Going from u to v or from v to u?(强联通,拓扑排序)
- poj Going from u to v or from v to u? 强联通缩点+拓扑排序(或搜索)
- poj2762 Going from u to v or from v to u?(强联通+拓扑排序)
- poj 2762 Going from u to v or from v to u?(缩点+拓扑排序)
- POJ--2762--Going from u to v or from v to u?【tarjan缩点+拓扑排序】
- poj 2762 Going from u to v or from v to u(targan缩点+拓扑排序)
- poj 2762 Going from u to v or from v to u?(SCC缩点+拓扑排序)
- POJ 2762 Going from u to v or from v to u? / 强连通分量&&拓扑
- POJ 2762 Going from u to v or from v to u?(强连通+拓扑)
- POJ 2762 — Going from u to v or from v to u? 强连通+拓扑
- poj 2762 Going from u to v or from v to u? (强连通+缩点+拓扑排序求解单项连通)
- POJ2762 Going from u to v or from v to u?(强连通分量缩点+拓扑排序)
- POJ2762 Going from u to v or from v to u? 强连通 Tarjan缩点+拓扑排序topsort
- poj2762 Going from u to v or from v to u?--trajan算法 & 强连通分量 & 缩点 & 拓扑排序
- 【POJ2762】Going from u to v or from v to u?(tarjan+缩点+拓扑排序)
- [POJ 2762]Going from u to v or from v to u? (强连通分量+拓扑排序)
- POJ 2762 Going from u to v or from v to u?(强连通分量+拓扑排序)
- 手写快速排序
- 46. 主元素
- 字节顺序
- 媒体查询@media
- POJ 2100 Graveyard Design
- POJ 2762【强联通缩点】【拓扑排序】Going from u to v or from v to u?
- 机器学习-导论
- lintcode有效的括号序列
- Git 常用操作(二)
- hdu5877 Weak Pair(dfs+线段树+离散化)
- Linux文件目录结构
- DOM操作
- pom.xml
- LinuxStudyNote(23)-Linux常用命令(3)-修改权限命令(2)chown、chgrp、umask、权限掩码