POJ 1637 Sightseeing tour (網絡流解決混合圖歐拉回路問題)

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

此題題意:給你n個點,m條邊,x,y,d表示哪兩個點相連,d=0表示爲雙向邊,d=1表示爲單向邊x->y,問你可不可能找出這麼一個點,使得從這個點出發,經過每條邊僅一次,然後回到該點,每條邊都必須走遍。
分析:歐拉回路分爲有向圖,無向圖,混合圖。顯然此題就是混合圖,既有有向邊,又有無向邊,下面粘貼一個在網上找到的關於歐拉回路的總結:

歐拉回路問題。
1 定義
歐拉通路 —— 通過圖中每條邊一次且僅一次,並且過每一頂點的通路。
歐拉回路——通過圖中每條邊一次且僅一次,並且過每一頂點的迴路。
歐拉圖——存在歐拉回路的圖。
2 無向圖是否具有歐拉通路或迴路的判定
G有歐拉通路的充分必要條件爲:G 連通,G中只有兩個奇度頂點(它們分別是歐拉通路的兩個端點)。
G有歐拉回路(G爲歐拉圖):G連通,G中均爲偶度頂點。
3 有向圖是否具有歐拉通路或迴路的判定
D有歐拉通路:D連通,除兩個頂點外,其餘頂點的入度均等於出度,這兩個特殊的頂點中,一個頂點的入度比出度大1,另一個頂點的入度比出度小1。
D有歐拉回路(D爲歐拉圖):D連通,D中所有頂點的入度等於出度。
4 混合圖。混合圖也就是無向圖與有向圖的混合,即圖中的邊既有有向邊也有無向邊。
5 混合圖歐拉回路(混合圖歐拉回路用的是網絡流)
把該圖的無向邊隨便定向(按題目給的默認順序就行),計算每個點的入度和出度。如果有某個點出入度之差爲奇數,那麼肯定不存在歐拉回路,因爲歐拉回路要求每點入度 = 出度,也就是總度數爲偶數,存在奇數度點必不能有歐拉回路。 現在每個點入度和出度之差均爲偶數。將這個偶數除以 2,得 x。即是說,對於每一個點,只要將 x 條邊反向(入>出就是x條入邊反向,出>入就是x條出邊反向,隨便畫個圖就明白),就能保證出 = 入。如果每個點都是出 = 入,那麼很明顯,該圖就存在歐拉回路。
現在的問題就變成了:該改變哪些邊,可以讓每個點出 = 入?構造網絡流模型。有向邊不能改變方向,直接刪掉(就是建圖時不用管,因爲不可變)。開始已定向的無向邊,定的是什麼向,就把網絡構建成什麼樣,邊長容量上限1。另新建 s 和 t。對於入 > 出的點 u,連接邊(u, t)、容量爲 x,對於出 > 入的點 v,連接邊(s, v),容量爲 x(注意對不同的點x不同)。之後,看是否有滿流的分配。有就是能有歐拉回路,沒有就是沒有。查看流值分配,將所有流量非 0(上限是 1,流值不是0就是1)的邊反向,就能得到每點入度 = 出度的歐拉圖。 由於是滿流,所以每個入 > 出的點,都有 x 條邊進來,將這些進來的邊反向,OK,入 = 出了。對於出 > 入的點亦然。那麼,沒和 s、t 連接的點怎麼辦?和s 連接的條件是出 > 入,和 t 連接的條件是入 > 出,那麼這個既沒和 s 也沒和 t 連接的點,自然早在開始就已經滿足入 = 出了。那麼在網絡流過程中,這些點屬於“中間點”。我們知道中間點流量不允許有累積的,這樣,進去多少就出來多少,反向之後,自然仍保持平衡。
dinici模板爲大白書上的模板:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
#include<algorithm>
#define maxn 2000
#define LL long long
#define inf 0x7fffffff
#define INF 1e18
using namespace std;
struct edge
{
    int from,to,cap,flow;
};
vector<edge> edges;
vector<int> G[maxn];
int d[maxn],cur[maxn];
bool vis[maxn];
int s,t;
void init()
{
    for(int i=0;i<maxn;i++) G[i].clear();
    edges.clear();
}
void add(int from,int to,int cap)
{
    edges.push_back((edge){from,to,cap,0});
    edges.push_back((edge){to,from,0,0});
    int m=edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}
bool bfs()
{
    memset(vis,false,sizeof(vis));
    memset(d,0,sizeof(d));
    queue<int> q;
    q.push(s);
    d[s]=0,vis[s]=true;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=0;i<G[x].size();i++)
        {
            edge& e=edges[G[x][i]];
            if(!vis[e.to]&&e.cap>e.flow)
            {
                vis[e.to]=true;
                d[e.to]=d[x]+1;
                q.push(e.to);
            }
        }
    }
    return vis[t];
}
int dfs(int x,int a)
{
    if(x==t||a==0) return a;
    int flow=0,f;
    for(int& i=cur[x];i<G[x].size();i++)
    {
        edge& e=edges[G[x][i]];
        if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
        {
            e.flow+=f;
            edges[G[x][i]^1].flow-=f;
            flow+=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int maxflow()
{
    int flow=0;
    while(bfs())
    {
        memset(cur,0,sizeof(cur));
        flow+=dfs(s,inf);
    }
    return flow;
}
int in[300],out[300];///記錄每個點的入度和出度
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int m,p,x,y,d;
        scanf("%d%d",&m,&p);
        init();
        s=0,t=m+1;
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=1;i<=p;i++)
        {
            scanf("%d%d%d",&x,&y,&d);
            in[y]++,out[x]++;
            if(!d) add(x,y,1);///無向邊建圖,有向邊不用管
        }
        int flog=1;
        for(int i=1;i<=m;i++)
        {
            if(abs(in[i]-out[i])&1)///入度和出度之差爲奇數,不存在這樣的歐拉回路
            {
                flog=0;
                break;
            }
        }
        if(!flog)
        {
            puts("impossible");
            continue;
        }
        int sum=0;
        for(int i=1;i<=m;i++)
        {
            if(in[i]>out[i]) add(i,t,(in[i]-out[i])>>1),sum+=(in[i]-out[i])>>1;
            if(in[i]<out[i]) add(s,i,(out[i]-in[i])>>1);
        }
        if(maxflow()==sum) puts("possible");
        else puts("impossible");
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章