POJ 1637 Sightseeing tour 最大流

判断混合图是否是欧拉图。

一个有向图是欧拉图if and only if每个节点的入度=出度。
由于一条无向边只能通过一次,最终经过这条边的时候总会有个方向,如果能为每条无向边定方向,使图满足上述条件那么混合图就存在欧拉图。

可以先随便定向,然后找出需要改向的边,使最终出入度相等。显然存在出入度差不为偶数的点的图不可能是欧拉图。

那么此时对于每个点存在入度与出度,表示为 inx;outx ,出入度平衡看作流量平衡,对于一条入边,如果改为出边,即入度-1,出度+1,相当于提供了2个单位的出流量,初始的由原有向边提供的入出度即入出流量可以由源汇点直接提供。

那么构图如下,先任意定向无向边后,统计各点的出入度,源点连向节点,容量为其入度,节点连向汇点,容量为其出度,对于每条定了向的边,建立方向反向的边,容量为2。

若源汇满流,即表明有向边的确都提供的流量,确保有向边的存在满足要求,答案可行。

下面程序的建图反了过来。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f, N = 10005, M = 600005;

int level[N], cnt, v[M], w[M], p[M], h[N], q[M], s, t;
void add(int a, int b, int c) {
    p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt;
    p[++cnt] = h[b]; v[cnt] = a; w[cnt] = 0; h[b] = cnt;
}

bool bfs() {
    int f = 0, r = 0, u, i;
    memset(level, -1, sizeof level);
    q[r++] = s; level[s] = 1;
    while (f < r) {
        u = q[f++];
        for (i = h[u]; i; i = p[i]) {
            if (w[i] && level[v[i]] == -1) {
                level[v[i]] = level[u] + 1;
                q[r++] = v[i];
            }
        }
    }
    return level[t] != -1;
}

int dfs(int u, int low) {
    int i, tmp = 0, res = 0;
    if (u == t) return low;
    for (i = h[u]; i && res < low; i = p[i]) {
        if (w[i] && level[v[i]] == level[u] + 1) {
            tmp = dfs(v[i], min(w[i], low - res));
            w[i] -= tmp; w[i ^ 1] += tmp; res += tmp;
        }
    }
    if (!res) level[u] = -1;
    return res;
}

int dinic() {
    int ans = 0;
    while (bfs()) ans += dfs(s, inf);
    return ans;
}
int d[N];
int main() {
    int i, a, b, c, tot, n, m, kase;
    scanf("%d", &kase);
    while (kase--) {
        scanf("%d%d", &n, &m);
        s = 0; t = n + 1; cnt = 1; tot = 0;
        memset(h, 0, sizeof h);
        memset(d, 0, sizeof d);
        for (i = 1; i <= m; ++i) {
            scanf("%d%d%d", &a, &b, &c);
            ++d[a]; --d[b];
            if (!c) add(a, b, 1);
        }
        for (i = 1; i <= n; ++i) {
            if (d[i] < 0) add(i, t, -d[i] / 2);
            if (d[i] > 0) add(s, i, d[i] / 2), tot += d[i] / 2;
        }
        bool flag = 1;
        for (i = 1; i <= n; ++i)
            if (d[i] & 1) { flag = 0; break; }
        if (flag && tot == dinic()) puts("possible");
        else puts("impossible");
    }
    return 0;
}

Sightseeing tour

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 8742 Accepted: 3671

Description

The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it’s possible to construct a sightseeing tour under these constraints.

Input

On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two positive integers m and s, 1 <= m <= 200,1 <= s <= 1000 being the number of junctions and streets, respectively. The following s lines contain the streets. Each street is described with three integers, xi, yi, and di, 1 <= xi,yi <= m, 0 <= di <= 1, where xi and yi are the junctions connected by a street. If di=1, then the street is a one-way street (going from xi to yi), otherwise it’s a two-way street. You may assume that there exists a junction from where all other junctions can be reached.

Output

For each scenario, output one line containing the text “possible” or “impossible”, whether or not it’s possible to construct a sightseeing tour.

Sample Input

4
5 8
2 1 0
1 3 0
4 1 1
1 5 0
5 4 1
3 4 0
4 2 1
2 2 0
4 4
1 2 1
2 3 0
3 4 0
1 4 1
3 3
1 2 0
2 3 0
3 2 0
3 4
1 2 0
2 3 1
1 2 0
3 2 0

Sample Output

possible
impossible
impossible
possible

Source

Northwestern Europe 2003

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值