POJ 1637 Sightseeing tour (欧拉路判定 网络流)

Sightseeing tour

Time Limit: 1000MS Memory Limit: 10000K
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

题目大意:给出一张混合图(有有向边,也有无向边),判断是否存在欧拉回路。

思路:
有向图存在欧拉回路条件:每个点处度等于入度。
首先是对图中的无向边随意定一个方向,之后再做调整。

统计每个点的入度和出度,如果入度- 出度是奇数的话,一定不存在欧拉回路。(因为每次调整出度和入度差会改变2)
现在每个点的出入度之差为偶数了,把这个偶数除以2,得x。则对每个顶点改变与之相连的x条边的方向就可以使得该点出入度相等。如果每个点都能达到出入度相等,自然就存在欧拉回路了。

有向边不能改变方向,所以不添加有向边。对于在开始的时候任意定向的无向边,按一开始假定的方向加边,容量为1(流了这个1就说明更改了这条边的方向)。源点向所有出>入的点连边(出>入的点一定可以流通,入>出的点就不一定了,会导致bfs建层次图是直接退出),容量为该点的x值;所有入>出的点向汇点连边,容量为该点的x值。

最后跑最大流,如果满流(最大流等于需要更改的入度或出度的总和,出>入的点不会将入边调整为出边,入>出的点不会将出边调整为入边,又因为所有点的总入度与所有点的总出度恒等,所以只要出度或入度满足条件那么就都满足条件了),则存在欧拉回路。因为满流分配,所以和源点相连的点一定都有x条边流入,将这些边反向这些点就出入度相等了,和汇点相连的亦然。没有和源、汇相连的已经出入度相等了,当然不用修改,所以保证了欧拉回路的存在。

#include <iostream>  
#include <cstring>  
#include<cstdio>  
#include <queue>   
using namespace std;  

const int maxn = 600;  
const int maxm = 500010;  
const int inf = 0x3f3f3f3f; 

int head[maxn],q[maxn],dis[maxn],last[maxn];
int n,m,idc,s,t,ans,sum,flag;  
int in[maxn], out[maxn];  

struct Edge{
    int to, next, w;
}ed[maxm];

void init(){
    idc = 1; ans = 0; sum = 0; flag = 0;
    memset(head, 0, sizeof(head));  
    memset(in, 0, sizeof(in));  
    memset(out, 0, sizeof(out)); 
    memset(ed, 0, sizeof(ed)); 
    memset(q, 0, sizeof(q));  
}  

void adde(int u, int v, int w){
    ed[++idc].to = v; 
    ed[idc].w = w;
    ed[idc].next = head[u];
    last[u]= head[u] = idc;
}  

bool bfs(){
    memset(dis, -1, sizeof(dis));
    int l=0, r=1;  
    q[1]=s; dis[s]=0;  
    while(l < r){
        int u = q[++l];  
        for(int k=head[u]; k; k=ed[k].next) {
            int v = ed[k].to;
            if(ed[k].w && dis[v] == -1){  
                dis[v] = dis[u] + 1;
                q[++r] = v;
                if(v == t) break;//到达 
            }
        }
    }
    for(int i=s; i<=t; i++){
        last[i] = head[i];
    }
    return dis[t] != -1;//能否到达 
}

int find(int u, int low){
    if (u==t || low==0) return low;  
    int totflow =0;
    for(int k=last[u]; k; last[u]=k=ed[k].next){//当前弧优化 
        int v = ed[k].to;
        if(ed[k].w && dis[v] == dis[u] + 1){
            int f = find(v, min(low,ed[k].w));  
            ed[k].w -= f; ed[k^1].w += f;  
            totflow += f; low -= f;
            //if(ed[k].w) last[u]=k;
            if(low == 0) return totflow;
        }
    }
    if( !totflow ) dis[u] = -1;//
    return totflow;  
}  

void Dinic(){
    while (bfs()) ans += find(s, inf);
}  

int main(){  
    int T; scanf("%d", &T);
    while( T-- ){  
        init();  
        scanf("%d%d", &n, &m);
        s = 0; t = n + 1;
        for(int i=1; i<=m; i++){
            int u, v, cc;
            scanf("%d%d%d", &u, &v, &cc);  
            out[u]++; in[v]++;  
            if( !cc ) adde(u, v, 1), adde(v, u, 0); 
        }  
        for(int i=1; i<=n; i++)  {  
            int d = in[i] - out[i];  
            if(d & 1) flag = 1;
            else if(d < 0){
                adde(s, i, (-d)>>1);
                adde(i, s, 0);  
            }
            else{
                adde(i, t, d>>1); 
                adde(t, i, 0);   
                sum += d >> 1;
            }
        }  
        Dinic(); 
        if(sum != ans) flag = 1;
        if(flag == 1) printf("impossible\n");  
        else printf("possible\n");  
    }  
    return 0;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值