poj 1637 Sightseeing tour 混合图欧拉回路 最大流 建图
题目链接
题意
给定一个混合图,里面既有有向边也有无向边。问该图中是否存在一条路径,经过每条边恰好一次。
思路
从欧拉回路说起
首先回顾有向图欧拉回路的充要条件:\(\forall v\in G, d_{in}(v)=d_{out}(v)\).
现在这个图中有一些无向边,那怎么办?
那就转化成有向边呀。
对无向边随意定向,得到一个有向图。在这个有向图中,如果有\(\forall v\in G, abs(d_{in}(v)-d_{out}(v))\)为偶数,则将其中一些边反向,肯定能得到一个欧拉图。而若为奇数,则肯定不可以。
为什么?可以有两种考虑方式:
1.将所有的边看成无向边,那么,“对于每个点来说入度与出度之差绝对值为偶数”,这个条件就意味着,“对于每个点其度(=入度+出度)为偶数”,而这正是无向图欧拉回路的充要条件。现在我们得到了这个无向图中的欧拉回路,一路走一路定向,就得到了有向图中的欧拉回路。对比原有向图中的边的方向与现在得到的欧拉回路中的边的方向,将其中一些反向即可。
2. 直接从修改的角度想,将一条边反向的效果是,它的两个端点的入度与出度之差都变化2,最终可以使得达到每个点的入度与出度之差为0的效果,即得到欧拉回路。
(第二种说得不太严谨...)
问题转化
但是这道题是不是这么简单的呢?并不是。
为什么?因为我们并不能将其中任意一条边随意反向,不然这就跟给了一张无向图没什么差别了。
所以,限制就在于:将限定范围内的一些边反向,问能否得到一个欧拉图。
于是问题转化为,现有一些点,其中一些入度\(\gt\)出度,另一些出度\(\gt\)入度。将其中一些边反向,问能否满足所有的点的入度\(==\)出度。
建图
由上面的关系可以很容易联想到网络流。
因为有向边是不可以反向的,所以对度数的改变没有任何贡献,不加入图中。
而经过定向成为有向边的边\(e=(u,v)\)在这一模型中的贡献是通过其反向可使\(u\)的入度-出度值增加\(2\),\(v\)的出度-入度值增加\(2\),故将之加入图中,权值为\(2\),意为将这一条边反向对度数的改变贡献为\(2\)。
接下来的步骤就很顺理成章了:
- 在 源点 到 出度\(\gt\)入度的点 之间加边,边权为出度与入度之差
- 在 入度\(\gt\)出度的点 到 汇点 之间加边,边权为入度与出度之差
最后只需判断最大流是否为满流即可。
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#define maxn 1010
#define maxm 10010
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
struct Edge { int to, ne, c; }edge[maxm];
int dep[maxn], ne[maxn], n, m, tot, s,t, out[maxn], in[maxn];
void add(int u, int v, int c) {
edge[tot] = {v, ne[u], c};
ne[u] = tot++;
edge[tot] = {u, ne[v], 0};
ne[v] = tot++;
}
int bfs(int src) {
memset(dep, 0, sizeof dep);
dep[src] = 1;
queue<int> q;
while (!q.empty()) q.pop();
q.push(src);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = ne[u]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (edge[i].c > 0 && !dep[v]) dep[v] = dep[u] + 1, q.push(v);
}
}
return dep[t];
}
int dfs(int u, int flow) {
if (u == t) return flow;
int ret = 0;
for (int i = ne[u]; ~i; i = edge[i].ne) {
int v = edge[i].to;
if (edge[i].c > 0 && dep[v] == dep[u] + 1) {
int c = dfs(v, min(flow-ret, edge[i].c));
edge[i].c -= c;
edge[i^1].c += c;
ret += c;
if (ret == flow) break;
}
}
if (!flow) dep[u] = 0;
return ret;
}
void work() {
scanf("%d%d", &n, &m);
tot = 0; memset(ne, -1, sizeof ne);
memset(out, 0, sizeof out); memset(in, 0, sizeof in);
s = 0, t = n+1;
for (int i = 0; i < m; ++i) {
int u, v, t;
scanf("%d%d%d", &u, &v, &t);
if (!t) add(u, v, 2);
++out[u], ++in[v];
}
int cnt=0;
for (int i = 1; i <= n; ++i) {
if (abs(out[i]-in[i])&1) { puts("impossible"); return; }
if (out[i] > in[i]) add(s, i, out[i]-in[i]), cnt += out[i]-in[i];
else if (out[i] < in[i]) add(i, t, in[i]-out[i]);
}
int ret=0,ans=0;
while (bfs(s)) {
while (ret = dfs(s, inf)) ans += ret;
}
if (ans == cnt) puts("possible");
else puts("impossible");
}
int main() {
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}
poj 1637 Sightseeing tour 混合图欧拉回路 最大流 建图的更多相关文章
- POJ 1637 Sightseeing tour ★混合图欧拉回路
[题目大意]混合图欧拉回路(1 <= N <= 200, 1 <= M <= 1000) [建模方法] 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为 ...
- POJ 1637 Sightseeing tour (混合图欧拉回路)
Sightseeing tour Description The city executive board in Lund wants to construct a sightseeing tou ...
- POJ 1637 Sightseeing tour(混合图的欧拉回路)
题目链接 建个图,套个模板. #include <cstdio> #include <cstring> #include <iostream> #include & ...
- POJ 1637 Sightseeing tour(最大流)
POJ 1637 Sightseeing tour 题目链接 题意:给一些有向边一些无向边,问能否把无向边定向之后确定一个欧拉回路 思路:这题的模型很的巧妙,转一个http://blog.csdn.n ...
- POJ 1637 - Sightseeing tour - [最大流解决混合图欧拉回路]
嗯,这是我上一篇文章说的那本宝典的第二题,我只想说,真TM是本宝典……做的我又痛苦又激动……(我感觉ACM的日常尽在这张表情中了) 题目链接:http://poj.org/problem?id=163 ...
- POJ 1637 Sightseeing tour(混合图欧拉回路+最大流)
http://poj.org/problem?id=1637 题意:给出n个点和m条边,这些边有些是单向边,有些是双向边,判断是否能构成欧拉回路. 思路: 构成有向图欧拉回路的要求是入度=出度,无向图 ...
- POJ 1637 Sightseeing tour (混合图欧拉路判定)
Sightseeing tour Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6986 Accepted: 2901 ...
- POJ 1637 Sightseeing tour (SAP | Dinic 混合欧拉图的判断)
Sightseeing tour Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 6448 Accepted: 2654 ...
- poj 1637 Sightseeing tour —— 最大流+欧拉回路
题目:http://poj.org/problem?id=1637 建图很妙: 先给无向边随便定向,这样会有一些点的入度不等于出度: 如果入度和出度的差值不是偶数,也就是说这个点的总度数是奇数,那么一 ...
随机推荐
- 无屏幕和键盘配置树莓派WiFi和SSH
原文转载:http://shumeipai.nxez.com/2017/09/13/raspberry-pi-network-configuration-before-boot.html 不算是什么新 ...
- Python 文件读写 文件和路径
1.在Windows上,使用倒斜杆作为文件夹之间的分隔符,在Linux上,使用正斜杠作为路径分隔符.在编写Python脚本时,可以os.path.join()函数来处理 在Windows环境下命令如下 ...
- Foxmail登录不了网易企业邮箱解决办法
关于Foxmail登录不了网易企业邮箱问题 解决办法是:在设置账号的时候手动设置pop服务器和smtp服务器. 新建账号的图: 点击“手动设置”出现如下界面: 设置完成后问题解决.下面的两个是正确的, ...
- 如何禁止js缓存?
<html> <head> <script type="text/javascript"> document.write("<s ...
- Python中的tuple
tuple_lst = [ ('元祖容器可哈希',), ('元祖中的元素不可直接修改',), ('元祖可迭代',), ('查',), ('练习',), ] 元祖容器可哈希 >>>ha ...
- ARM linux中断总结
Linux异常处理体系结构 Linux异常体系之vector_stub宏解析 Linux异常体系之stubs_offset Linux中断体系结构 ARM系统调用
- MySQL创建数据库及用户
create database ${db_name} default charset utf8 COLLATE utf8_general_ci; grant all on ${db_name}.* t ...
- kettle - Linux下定时执行kettle作业
Linux下实现kettle 自动同步数据 1.安装jdk tar -zxvf jdk-7u25-linux-x64.tar.gz -C /usr/share 2.配置java环境 vim /etc/ ...
- [译]Exactly once is NOT exactly the same
近日学习Pulsar文档时,注意到Pulsar提到其提供的是effectively-once语义,而不是其它流计算引擎announce的exactly-once语义,并引用了Exactly once ...
- oracle 基本函数
1)字符串函数---length()函数 用于返回字符串长度 select t.name,length(t.name) from tb_person t 2)向左补全字符串---LPAD()函数 L ...