1. 程式人生 > >POJ1637:Sightseeing tour(混合圖的歐拉回路)

POJ1637:Sightseeing tour(混合圖的歐拉回路)

Sightseeing tour

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 10581   Accepted: 4466

題目連結:http://poj.org/problem?id=1637

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

題意:

輸入包含多組資料,然後給出一個混合圖(既有有向邊也有無向邊),現在問是否能從一個起點出發,經過每一條邊一次又重新回到這一個點。

PS:雙向邊也只能經過一次。

 

題解:

如果這個題就為單純的有向圖或者無向圖就好辦了,我們只需要判斷每個點的入度和出度就ok了,但這是混合圖....反正我開始並沒想到用最大流= =

對於尤拉路徑,最不可少的就是每個點入度和出度的度數了,我們還是可以統計每個點的入度、出度度數。

假設對於一個點來說,如果將一條邊反向,入度和出度的變化之和為0。我們就可以利用這一性質來判斷可行性。

假定現在存在了尤拉路徑,說明我們至少有一種將一些邊反向的方案能夠滿足條件。

對於雙向邊而言,我們就先假定任意一個方向然後再來統計度數並且加邊,有向邊邊權為0,意即流不能從這條邊通過。

我們假定最大流經過的邊就是能夠反向的邊,那麼我們將每條“有向邊”(其實是無向邊)的容量設定為1即可。

對於源點和匯點,假如一個點當前的入度大於出度,那麼源點與之相連,邊權為(入度-出度)/2(意即需要將多少邊反向);對於匯點也同理。

最後我們跑最大流看看能否滿流就行了。

思路還是很巧妙的,主要就在於定無向為有向,再利用最大流來考慮將邊反向。

 

程式碼如下:

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#define s 0
#define t n+1
#define INF 1e9
using namespace std;
typedef long long ll;
const int N = 205,M = 1005;
int n,m,T,tot;
int head[N],in[N],out[N],d[N];
struct Edge{
    int v,next,c;
}e[M<<2];
void adde(int u,int v,int c){
    e[tot].v=v;e[tot].next=head[u];e[tot].c=c;head[u]=tot++;
    e[tot].v=u;e[tot].next=head[v];e[tot].c=0;head[v]=tot++;
}
bool bfs(int S,int T){
    memset(d,0,sizeof(d));d[S]=1;
    queue <int > q;q.push(S);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i!=-1;i=e[i].next){
            int v=e[i].v;
            if(!d[v] && e[i].c>0){
                d[v]=d[u]+1;
                q.push(v);
            }
        }
    }
    return d[T]!=0;
}
int dfs(int S,int a){
    int flow=0,f;
    if(S==t || a==0) return a;
    for(int i=head[S];i!=-1;i=e[i].next){
        int v=e[i].v;
        if(d[v]!=d[S]+1) continue ;
        f=dfs(v,min(a,e[i].c));
        if(f){
            e[i].c-=f;
            e[i^1].c+=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    if(!flow) d[S]=-1;
    return flow;
}
int Dinic(){
    int max_flow=0;
    while(bfs(0,t)){
        max_flow+=dfs(0,INF);
    }
    return max_flow;
}
int main(){
    scanf("%d",&T);
    while(T--){
        tot=0;memset(head,-1,sizeof(head));
        memset(in,0,sizeof(in));memset(out,0,sizeof(out));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            int u,v,op;
            scanf("%d%d%d",&u,&v,&op);
            if(op==0) adde(u,v,1);
            else adde(u,v,0);
            in[v]++;out[u]++;
        }
        int flag=1,sum=0;
        for(int i=1;i<=n;i++){
            int now = in[i]-out[i];
            if(now&1) flag=0;
            if(now>0) adde(i,t,now/2);
            if(now<=0) adde(s,i,-now/2),sum+=now/2;
        }
        sum=-sum;
        if(!flag){
            puts("impossible");
            continue ;
        }
        int flow = Dinic();
        if(flow==sum) puts("possible");
        else puts("impossible");
    }
    return 0;
}