POJ1637.Sightseeing tour(观光旅游线)——混合图的欧拉回路

http://poj.org/problem?id=1637

转自kuangbin巨巨
http://www.cnblogs.com/kuangbin/p/3537525.html

一个混合图,既含无向边又含有向边
对无向边任取一个方向,将混合图变为有向图,转变为有向图后,根据有向图欧拉通路/回路的充要条件,进行判断
1.有向图是欧拉图当且仅当是强连通的且每个顶点的入度等于出度
2.有向图是半欧拉图当且仅当是单向连通的且恰有两个奇度顶点,其中一个顶点的入度比出度大1,另一个顶点的出度比入度大1

记D[i]=out[i]-in[i]
1.如果D[i]>0,则source与i连边,cap为D[i]/2;
2.如果D[i]<0,则i与sink连边,cap为D[i]/2;
求一次最大流,如果满流,则存在欧拉回路/通路

//176K  16MS    C++
#include<cstdio>
#include<cstring>
const int MAXN=220;
const int MAXM=4000;
const int INF=0x3f3f3f3f;
int n,s,t,N;//输入的顶点数,源点,汇点,总顶点数
int m;
int in[MAXN],out[MAXN];

struct Edge{
    int to,next,cap,flow;
}edge[MAXM];
int head[MAXN],tot,gap[MAXN],d[MAXN],cur[MAXN],que[MAXN],p[MAXN];
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}
void addedge(int u,int v,int c){
    edge[tot].to=v;
    edge[tot].cap=c;
    edge[tot].flow=0;
    edge[tot].next=head[u];
    head[u]=tot++;
    edge[tot].to=u;
    edge[tot].cap=0;
    edge[tot].flow=0;
    edge[tot].next=head[v];
    head[v]=tot++;
}
void BFS(){
    memset(d,-1,sizeof(d));
    memset(gap,0,sizeof(gap));
    gap[0]=1;
    int front=0,rear=0;
    d[t]=0;
    que[rear++]=t;
    while(front!=rear){
        int u=que[front++];
        for(int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(d[v]!=-1) continue;
            que[rear++]=v;
            d[v]=d[u]+1;
            gap[d[v]]++;
        }
    }
}
int isap(){
    BFS();
    memcpy(cur,head,sizeof(head));
    int top=0,x=s,flow=0;
    while(d[s]<N){
        if(x==t){
            int Min=INF,inser;
            for(int i=0;i<top;++i){
                if(Min>edge[p[i]].cap-edge[p[i]].flow){
                    Min=edge[p[i]].cap-edge[p[i]].flow;
                    inser=i;
                }
            }
            for(int i=0;i<top;++i){
                edge[p[i]].flow+=Min;
                edge[p[i]^1].flow-=Min;
            }
            flow+=Min;
            top=inser;
            x=edge[p[top]^1].to;
            continue;
        }
        int ok=0;
        for(int i=cur[x];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(edge[i].cap>edge[i].flow&&d[v]+1==d[x]){
                ok=1;
                cur[x]=i;
                p[top++]=i;
                x=edge[i].to;
                break;
            }
        }
        if(!ok){
            int Min=n+n+2;
            for(int i=head[x];i!=-1;i=edge[i].next){
                if(edge[i].cap>edge[i].flow&&d[edge[i].to]<Min){
                    Min=d[edge[i].to];
                    cur[x]=i;
                }
            }
            if(--gap[d[x]]==0) break;
            gap[d[x]=Min+1]++;
            if(x!=s) x=edge[p[--top]^1].to;
        }
    }
    return flow;
}
void Build_graph(){
    s=0,t=n+1,N=t+1;
    bool flag=true;
    for(int i=1;flag&&i<=n;++i){
        if(out[i]-in[i]>0) addedge(s,i,(out[i]-in[i])/2);
        else if(in[i]-out[i]>0) addedge(i,t,(in[i]-out[i])/2);
        if((out[i]-in[i])&1) flag=false;
    }
    if(!flag) printf("impossible\n");
    else{
        isap();
        for(int i=head[0];flag&&i!=-1;i=edge[i].next){
            if(edge[i].cap>edge[i].flow) flag=false;
        }
        if(!flag) printf("impossible\n");
        else printf("possible\n");
    }
}
int main()
{
    int T,u,v,w;
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;++i){
            scanf("%d%d%d",&u,&v,&w);
            in[v]++,out[u]++;
            if(w==0) addedge(u,v,1);
        }
        Build_graph();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值