[CQOI2013]图的逆变换
2015-08-24 16:50
239 查看
题意
给一个n结点m条边的有向图D,可以这样构造图E:给D的每条边u->v,在E中建立一个点uv,然后对于D中的两条边u->v和v->w,在E中从uv向vw连一条有向边。E中不含有其他点和边。输入E,你的任务是判断是否存在相应的D。注意,D可以有重边和自环。
测试数据个数T≤10T \le 10
DD的边数(即EE的点数)m≤300m \le 300
TimeTime Limits:2000msLimits:2000ms
MemoryMemory Limits:512000KBLimits:512000KB
分析
设OutuOut_u为EE中uu点出边指向的点的集合。我们会有一个结论:若存在DD,∀u,v\forall u,v Outu=Outv Out_u =Out_v or Outu∩Outv=ϕOut_u \cap Out_v = \phi结论必要性显然,充分性引用题解里的证明:可以尝试构造出一个可能的图 G。对于每一个 u,找到的若干 x, y的导出子图是一个完全二分图,对左部在图 G 中对应的边到达的点和右部在图 G 中对应的边出发的点规定为 G 中一个全新的节点即可。
这样我们可以用并查集,对于点uu,将OutuOut_u里的点并一起,并记录并查集的大小。最后扫一遍,看每个点OutOut集合大小是否跟并查集大小相等。
代码
#include <cstdio> #include <cstring> using namespace std; const int N = 310,M = 1e6; int g ,next[M],to[M],d ,f ,size ; int tot,n,k; void add(int x,int y) { to[++ tot] = y; next[tot] = g[x]; g[x] = tot; d[x] ++; } int get(int x) { if (f[x] != x) f[x] = get(f[x]); return f[x]; } int main() { int T; scanf("%d",&T); while (T --) { memset(g,0,sizeof(g)); memset(d,0,sizeof(d)); tot = 0; scanf("%d%d",&n,&k); for (int i = 0;i < n;i ++) f[i] = i,size[i] = 1; for (int i = 1;i <= k;i ++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } for (int i = 0;i < n;i ++) if (g[i]) { int j,last = to[g[i]]; int y = get(last); for (j = next[g[i]];j;j = next[j]) { int x = get(to[j]); if (x == y) continue; f[x] = y; size[y] += size[x]; } } int flag = 1; for (int i = 0;i < n;i ++) if (g[i]) { int j = get(to[g[i]]); if (size[j] != d[i]) { flag = 0; break; } } if (flag) printf("Yes\n"); else printf("No\n"); } }
相关文章推荐
- C++中的继承和组合区别使用
- C++中的三种继承public,protected,private
- linux free 命令
- Excel自定义格式详解
- JS 操作cookie概
- ion-tabs接口文档:Delegate: $ionicTabsDelegate
- android消息推送
- 缓存
- LAMP搭建
- npm(node)的安装步骤
- JAVA 得到两日期相差几个月
- 关于"引用"的几点说明
- GDI双缓冲绘图
- PL/SQL Developer调试存储过程,函数
- Spring JdbcTemplate的batchUpdate中,没有看到conn.setAutoCommit(false)的操作
- Http Header之User-Agent
- 黑马程序员_面向对象之封装
- jboss CLI 命令行接口学习(适用JBOSS EAP 6.2+)
- 企业模式之Unit Of Work模式
- 关于C++中的友元函数的总结