1. 程式人生 > >[POJ1637]Sightseeing tour:混合圖歐拉回路

[POJ1637]Sightseeing tour:混合圖歐拉回路

分析

混合圖歐拉回路問題。

一個有向圖有歐拉回路當且僅當圖連通並且對於每個點,入度\(=\)出度。

入度和出度相等可以聯想到(我也不知道是怎麼聯想到的)網路流除了源匯點均滿足入流\(=\)出流。於是可以考慮先將無向邊隨意定向後,通過網路流來調整無向邊的方向以達到每個點的入度和出度相等的目的。

建圖方法如下:

  1. \(outdeg[x]>indeg[x]\),則從\(S\)\(x\)連一條容量為\(\frac{outdeg[x]-indeg[x]}{2}\)的邊。

  2. \(outdeg[x]<indeg[x]\),則從\(x\)\(T\)連一條容量為\(\frac{indeg[x]-outdeg[x]}{2}\)

    的邊。

  3. 將每一條你定向的有向邊令其容量為\(1\)加入到網路中。

這樣一條增廣路的意義就是將路徑上的邊全部取反,然後將第一個結點的入度\(++\),出度\(--\),將最後一個結點的入度\(--\),出度\(++\)

怎麼判無解?

把所有邊都看作無向邊,那麼如果存在一個節點的度數為奇數,直接輸出impossible即可。

程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <queue>
#define rin(i,a,b) for(register int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[x];i;i=e[i].nxt)
typedef long long LL;
using std::cin;
using std::cout;
using std::endl;

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}

const int MAXN=205;
const int MAXM=1005;
int n,m,S,T,maxflow,ecnt,head[MAXN];
int indeg[MAXN],outdeg[MAXN],dep[MAXN],cur[MAXN];
std::queue<int> q;
struct Edge{
    int to,nxt,cap;
}e[MAXM*2+MAXN*2];

inline void add_edge(int bg,int ed,int ca){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    e[ecnt].cap=ca;
    head[bg]=ecnt;
}

inline bool bfs(){
    memset(dep,0,sizeof dep);
    rin(i,1,T) cur[i]=head[i];
    while(!q.empty()) q.pop();
    q.push(S);
    dep[S]=1;
    while(!q.empty()){
        int x=q.front();q.pop();
        trav(i,x){
            int ver=e[i].to;
            if(dep[ver]||!e[i].cap) continue;
            dep[ver]=dep[x]+1;
            q.push(ver);
        }
    }
    return dep[T]>0;
}

int dfs(int x,int pref){
    if(x==T||!pref) return pref;
    int flow=0,temp;
    for(int &i=cur[x];i;i=e[i].nxt){
        int ver=e[i].to;
        if(dep[ver]==dep[x]+1&&(temp=dfs(ver,std::min(pref,e[i].cap)))){
            e[i].cap-=temp;
            e[i^1].cap+=temp;
            flow+=temp;
            pref-=temp;
            if(!pref) return flow;
        }
    }
    return flow;
}

inline void dinic(){
    while(bfs()) maxflow+=dfs(S,1e9);
}

int main(){
    int TT=read();
    while(TT--){
        ecnt=1;memset(head,0,sizeof head);
        memset(indeg,0,sizeof indeg);
        memset(outdeg,0,sizeof outdeg);
        maxflow=0; 
        n=read(),m=read();S=n+1,T=S+1;
        rin(i,1,m){
            int u=read(),v=read(),typ=read();
            if(!typ){
                add_edge(u,v,1);
                add_edge(v,u,0);
                outdeg[u]++;
                indeg[v]++;
            }
            else{
                outdeg[u]++;
                indeg[v]++;
            }
        }
        bool flag=0;
        rin(i,1,n){
            flag|=((outdeg[i]+indeg[i])&1);
        }
        if(flag){
            printf("impossible\n");
            continue;
        }
        int temp=0;
        rin(i,1,n){
            if(outdeg[i]>indeg[i]){
                add_edge(S,i,(outdeg[i]-indeg[i])/2);
                add_edge(i,S,0);
                temp+=(outdeg[i]-indeg[i])/2;
            }
            else if(outdeg[i]<indeg[i]){
                add_edge(i,T,(indeg[i]-outdeg[i])/2);
                add_edge(T,i,0);
            }
        }
        dinic();
        if(maxflow<temp) printf("impossible\n");
        else printf("possible\n");
    }
    return 0;
}