poj1637 Sightseeing tour (混合图欧拉回路)
2015-01-13 20:38
225 查看
有向图存在欧拉回路的条件:所有点入度=出度。
对于混合图,可以先把所有的无向边假设一个方向。
但是所有的假设不一定都正确,此时需要调整边的方向。
怎样调整呢?这是就要使用网络流。
设每个点入度为in[i],出度为out[i],
对于每一个点i,如果in[i] > out[i],从源点到i连一条容量为(in[i] - out[i]) / 2的边,
如果out[i] > in[i],从i到汇点连一条容量为(out[i] - in[i]) / 2的边。
若两点i,j之间有cnt[i][j]条无向边,从j到i连一条容量为cnt[i][j]的边。
求一次最大流,如果满流则有解,否则无解。
代码:
对于混合图,可以先把所有的无向边假设一个方向。
但是所有的假设不一定都正确,此时需要调整边的方向。
怎样调整呢?这是就要使用网络流。
设每个点入度为in[i],出度为out[i],
对于每一个点i,如果in[i] > out[i],从源点到i连一条容量为(in[i] - out[i]) / 2的边,
如果out[i] > in[i],从i到汇点连一条容量为(out[i] - in[i]) / 2的边。
若两点i,j之间有cnt[i][j]条无向边,从j到i连一条容量为cnt[i][j]的边。
求一次最大流,如果满流则有解,否则无解。
代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> #include <queue> #define INF 0x3f3f3f3f #define T (n + 1) using namespace std; struct Edge{ int from, to, cap, flow; Edge() {} Edge(int a, int b, int c, int d) : from(a), to(b), cap(c), flow(d) {} }; int cas; int n, m; int in[205], out[205]; int cnt[205][205]; // cnt[i][j]表示节点i与节点j之间有多少无向边。 vector<Edge> edges; vector<int> G[205]; void addEdge(int from, int to, int cap) { edges.push_back(Edge(from, to, cap, 0)); edges.push_back(Edge(to, from, 0, 0)); int siz = edges.size(); G[from].push_back(siz - 2); G[to].push_back(siz - 1); } void buildGraph() { for (int i = 1; i <= n; i++) { if (in[i] > out[i]) addEdge(0, i, (in[i] - out[i]) >> 1); if (out[i] > in[i]) addEdge(i, T, (out[i] - in[i]) >> 1); for (int j = 1; j <= n; j++) if (cnt[i][j]) addEdge(j, i, cnt[i][j]); } } int cur[205]; int layer[205]; bool build() { memset(layer, -1, sizeof(layer)); queue<int> q; q.push(0); layer[0] = 0; while (!q.empty()) { int current = q.front(); q.pop(); for (int i = 0; i < G[current].size(); i++) { Edge e = edges[G[current][i]]; if (layer[e.to] == -1 && e.cap > e.flow) { layer[e.to] = layer[current] + 1; q.push(e.to); } } } return layer[T] != -1; } int find(int x, int curflow) { if (x == T || !curflow) return curflow; int f, flow = 0; for (int &i = cur[x]; i < G[x].size(); i++) { Edge &e = edges[G[x][i]]; if (layer[e.to] == layer[x] + 1 && (f = find(e.to, min(curflow, e.cap - e.flow)))) { e.flow += f; edges[G[x][i] ^ 1].flow -= f; flow += f; curflow -= f; if (!curflow) break; } } return flow; } int dinic() { int maxflow = 0; while (build()) { memset(cur, 0, sizeof(cur)); maxflow += find(0, INF); } return maxflow; } int main() { freopen("1637.in", "r", stdin); scanf("%d", &cas); while (cas--) { scanf("%d %d", &n, &m); memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); memset(cnt, 0, sizeof(cnt)); for (int i = 0; i <= n; i++) G[i].clear(); edges.clear(); int a, b, c; for (int i = 0; i < m; i++) { scanf("%d %d %d", &a, &b, &c); in[b]++; out[a]++; if (!c) cnt[a][b]++; } int flow = 0; // 总共需要调整的边 bool flag = true; for (int i = 1; i <= n; i++) { if (in[i] > out[i]) flow += (in[i] - out[i] >> 1); // 如果一个点入度大于出度x,那么就需要调整x/2条边 if (abs(in[i] - out[i]) & 1) { // 如果一个点入度-出度的绝对值为奇数 flag = false; // 一定不存在欧拉回路 break; } } if (!flag) { printf("impossible\n"); continue; } buildGraph(); int maxflow = dinic(); if (maxflow == flow) printf("possible\n"); else printf("impossible\n"); } return 0; }
相关文章推荐
- 【poj1637】Sightseeing tour 混合图欧拉回路(最大流)
- POJ1637.Sightseeing tour(观光旅游线)——混合图的欧拉回路
- 【POJ1637】Sightseeing tour 混合图求欧拉回路存在性 网络流、
- [POJ1637]Sightseeing tour 混合图欧拉回路 做题笔记
- 【POJ1637】Sightseeing tour【最大流】【混合图欧拉回路】
- POJ1637 Sightseeing tour(判定混合图欧拉回路)
- poj 1637 Sightseeing tour 【网络流 求解混合欧拉回路是否存在】
- Sightseeing tour POJ - 1637(混合欧拉回路判定)
- ZOJ 1992 Sightseeing Tour(混合图欧拉回路)
- POJ 1637 Sightseeing tour (混合图欧拉回路,网络最大流)
- POJ 1637 Sightseeing tour 混合欧拉回路
- 【最大流+混合图欧拉回路】POJ-1637 Sightseeing tour
- POJ1637 Sightseeing tour(混合图欧拉回路判定)
- POJ 1637 Sightseeing tour (网络流解决混合图欧拉回路问题)
- POJ 637 Sightseeing tour 混合欧拉回路 最大流
- poj1637 Sightseeing tour,混合图的欧拉回路问题,最大流解
- ZOJ 1992 Sightseeing Tour(混合图欧拉回路)
- POJ 1637 Sightseeing tour (混合图欧拉回路)
- poj1637 Sightseeing tour 网络流 混合图的欧拉回路
- POJ 1637 Sightseeing tour(混合图的欧拉回路)