POJ 1637 Sightseeing tour

kuangbin把这道题的难度设置为 crazy …… 搞得我都不太敢刷……

题意:
混合图中欧拉回路的判定

思路:
这道题是真的不好想,最后还是去看了题解,因为比较典型 好吧是我菜
混合图欧拉回路无法用普通的定理去判定,不行可以试试……网络流建模给出的思想是将无向边任意转化成有向边,再去通过变换无向边的方向来实现欧拉回路。

建图方式:

  • 对无向边建立你所设定的方向,容量为1
  • 对于每个点,如果入度与出度差的绝对值为奇数,则不存在欧拉回路。 ( 因为反转一条边,则两个点的入度出度差各自变化 2 )
  • 否则 ,对于每个点如果 入度>出度 则为 汇点,与超级汇点容量为 ( 入度 – 出度 ) / 2 ,反之则为源点,与超级源点容量为 ( 出度 – 入度 ) / 2 。

跑一遍dinic即可。

残余网络中流量不为0的边即为反转边。这样求出欧拉路径也不算什么难事了。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>

using namespace std;
const int maxn = 410;
const int inf = 0x3f3f3f3f;

int n, m, idx, st, en;
int dis[maxn][maxn];
int level[maxn], cur[maxn], que[maxn * maxn];
int head[maxn];
int indegree[maxn], outdegree[maxn], subdegree[maxn];

struct node {
    int flow;
    int to;
    int nxt;
} edges[20005];

void addEdge(int u, int v, int f)
{
    edges[idx].to = v;
    edges[idx].flow = f;
    edges[idx].nxt = head[u];
    head[u] = idx++;

    edges[idx].to = u;
    edges[idx].flow = 0;
    edges[idx].nxt = head[v];
    head[v] = idx++;
}

bool bfs()
{
    memset(level, -1, sizeof level);
    que[0] = st;
    level[st] = 0;
    int l = 0, r = 1, u;
    while (l < r) {
        u = que[l++];
        for (int id = head[u]; ~id; id = edges[id].nxt) {
            int v = edges[id].to;
            if (edges[id].flow && level[v] == -1) {
                level[v] = level[u] + 1;
                que[r++] = v;
            }
        }
    }
    return level[en] != -1;
}

int dfs(int u, int low)
{
    int cflow;
    if (u == en)
        return low;
    for (int& id = cur[u]; ~id; id = edges[id].nxt) {
        int v = edges[id].to;
        if (edges[id].flow > 0 && level[v] == level[u] + 1
            && (cflow = dfs(v, min(low, edges[id].flow)))) {
            edges[id].flow -= cflow;
            edges[id ^ 1].flow += cflow;
            return cflow;
        }
    }
    return 0;
}

int dinic()
{
    int ans = 0, cflow;
    while (bfs()) {
        for (int i = 0; i <= 2 * n; i++)
            cur[i] = head[i];
        while ((cflow = dfs(st, inf)))
            ans += cflow;
    }
    return ans;
}

int main()
{
    int T, u, v, op;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &m);
        memset(head, -1, sizeof head);
        memset(indegree, 0, sizeof indegree);
        memset(outdegree, 0, sizeof outdegree);
        idx = 0;
        st = 0, en = n + 1;
        for (int i = 0; i < m; i++) {
            scanf("%d %d %d", &u, &v, &op);
            if (u == v)
                continue;
            outdegree[u]++;
            indegree[v]++;
            if (!op)
                addEdge(u, v, 1);
        }
        bool flag = true;
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            if (outdegree[i] > indegree[i]) {
                if ((outdegree[i] - indegree[i]) & 1) {
                    flag = false;
                    break;
                } else {
                    addEdge(0, i, (outdegree[i] - indegree[i]) / 2);
                    sum += (outdegree[i] - indegree[i]);
                }
            } else if (outdegree[i] < indegree[i]) {
                if ((indegree[i] - outdegree[i]) & 1) {
                    flag = false;
                    break;
                } else
                    addEdge(i, n + 1, (indegree[i] - outdegree[i]) / 2);
            }
        }
        if (!flag)
            puts("impossible");
        else {
            if (dinic() == sum / 2)
                puts("possible");
            else
                puts("impossible");
        }
    }
    return 0;
}