poj 1637 Sightseeing tour 【网络流 求解混合欧拉回路是否存在】

来源:互联网 发布:手机作曲编曲软件 编辑:程序博客网 时间:2024/05/01 07:09
Sightseeing tour
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 8331 Accepted: 3522

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

45 82 1 01 3 04 1 11 5 05 4 13 4 04 2 12 2 04 41 2 12 3 03 4 01 4 13 31 2 02 3 03 2 03 41 2 02 3 11 2 03 2 0

Sample Output

possibleimpossibleimpossible

possible

题意:给你N个点和M条边,边的信息有三个(a, b, c),若c为0代表边是无向的,反之边是有向的且从a到b。问你欧拉回路是否存在。

混合图判断欧拉回路,我们肯定要考虑有向图欧拉回路的性质——即每个点的入度等于出度。

思路:对每条边<a, b>,若它是无向的,我们把它人为定向并建一条边容量为1的边,并按照建立的这条边的方向来记录点的出度in[]和入度out[]。首先对于任意的点i,in[i] - out[i]的绝对值必须是偶数,这样才符合欧拉回路的性质。在满足该条件的前提下,我们若能合理分配剩余度数(in和out的差值),那么欧拉回路必存在。

我们可以构建网络流模型,判断剩余度数能否完全分配。下面需要确定的是模型中边的方向.

假设我们定向原图中边<u, v>方向为u -> v。

1,当u的出度大于入度,才可能把多的出度分配给v,当做v的入度。这个度数能否成功分配可以用能否到达汇点sink来判定。

2,当u的出度小于入度,v是不可能把多的出度分配给u的,因为v->u没有边。这个时候我们必须要从source给点u分配度数。

这样建边方向就出来了,若确定无向边<u, v>方向为u -> v。

那么当点的in < out时,源点source向它建边,容量为差值的一半。当点的out > in时,它向汇点建边,容量为差值的一半。

建图:设置超级源点source,超级汇点sink。

1,对于边<u, v>,若它是无向的,我们人为定向,u向v建边,容量为1。当欧拉路径中是v -> u的,u多出的度数可以流到v。

2,若in[i] < out[i],则source向i建边,容量为正差值的一半;

3,若in[i] > out[i],则i向sink建边,容量为正差值的一半。

统计从source流入的流量sum,最后判断是否满流即可。

AC代码:

#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#define MAXN 400#define MAXM 50000#define INF 0x3f3f3f3fusing namespace std;struct Edge{    int from, to, cap, flow, next;};Edge edge[MAXM];int head[MAXN], edgenum;int dist[MAXN], cur[MAXN];bool vis[MAXN];int N, M;void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w){    Edge E1 = {u, v, w, 0, head[u]};    edge[edgenum] = E1;    head[u] = edgenum++;    Edge E2 = {v, u, 0, 0, head[v]};    edge[edgenum] = E2;    head[v] = edgenum++;}int in[MAXN], out[MAXN];bool flag;int source, sink;int sum;//记录总流量void getMap(){    init();    scanf("%d%d", &N, &M);    int a, b, c;    memset(in, 0, sizeof(in));    memset(out, 0, sizeof(out));    for(int i = 0; i < M; i++)    {        scanf("%d%d%d", &a, &b, &c);        if(a == b) continue;        if(c == 0)            addEdge(a, b, 1);        //addEdge(a, b, INF);        in[b]++, out[a]++;    }    source = 0, sink = N+1;    flag = true;    sum = 0;    for(int i = 1; i <= N; i++)    {        int k = abs(in[i] - out[i]);        if(k & 1)//奇数 必没有欧拉回路        {            flag = false;            break;        }        k /= 2;        if(in[i] < out[i])            addEdge(source, i, k), sum += k;        else            addEdge(i, sink, k);    }}bool BFS(int s, int t){    queue<int> Q;    memset(dist, -1, sizeof(dist));    memset(vis, false, sizeof(vis));    dist[s] = 0;    vis[s] = true;    Q.push(s);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && E.cap > E.flow)            {                dist[E.to] = dist[u] + 1;                if(E.to == t) return true;                vis[E.to] = true;                Q.push(E.to);            }        }    }    return false;}int DFS(int x, int a, int t){    if(x == t || a == 0) return a;    int flow = 0, f;    for(int &i = cur[x]; i != -1; i = edge[i].next)    {        Edge &E = edge[i];        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap-E.flow), t)) > 0)        {            edge[i].flow += f;            edge[i^1].flow -= f;            flow += f;            a -= f;            if(a == 0) break;        }    }    return flow;}int Maxflow(int s, int t){    int flow = 0;    while(BFS(s, t))    {        memcpy(cur, head, sizeof(head));        flow += DFS(s, INF, t);    }    return flow;}void solve(){    if(!flag)    {        printf("impossible\n");        return ;    }    //printf("%d %d\n", Maxflow(source, sink), sum);    if(Maxflow(source, sink) == sum)        printf("possible\n");    else        printf("impossible\n");}int main(){    int t;    scanf("%d", &t);    while(t--)    {        getMap();        solve();    }    return 0;}


0 0