2414: Sightseeing tour 混合图欧拉回路+网络流

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

 

//

 

判断一个图中是否存在欧拉回路(每条边恰好只走一次,并能回到出发点的路径),在以下三种情况中有三种不同的算法:

每个顶点的度数都是偶数,则存在欧拉回路。

每个节顶点的入度都等于出度,则存在欧拉回路。.混合图欧拉回路

  把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度

  好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以x。也就是说,对于每一个点,只要将>出就是变入,出 = 入。如果每个点都是出

  现在的问题就变成了:我该改变哪些边,可以让每个点出1。另新建t。对于入u,连接边x,对于出v,连接边x(注意对不同的点 0(上限是0就是 = 出度的欧拉图。 >出的点,都有OK,入 > 入的点亦然。那么,没和t连接的点怎么办?和 > 入,和 >出,那么这个既没和t连接的点,自然早在开始就已经满足入

  所以,就这样,混合图欧拉回路问题,解了。

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=(1<<28);
const int point_num=500;
int cap[point_num][point_num],dist[point_num],gap[point_num];//初始化见main里面
int s0,t0,n;//源,汇和点数
int find_path(int p,int limit=0x3f3f3f3f)
{
    if(p==t0)   return limit;
    for(int i=0;i<n;i++)
    if(dist[p]==dist[i]+1  &&  cap[p][i]>0)
    {
       int t=find_path(i,min(cap[p][i],limit));
       if(t<0)   return t;
       if(t>0)
       {
            cap[p][i]-=t;
            cap[i][p]+=t;
            return t;
       }
    }
    int label=n;
    for(int i=0;i<n;i++)  if(cap[p][i]>0)  label=min(label,dist[i]+1);
    if(--gap[dist[p]]==0  ||  dist[s0]>=n )   return -1;
    ++gap[dist[p]=label];
    return 0;
}
int sap()
{
    memset(dist,0,sizeof(dist));
    memset(gap,0,sizeof(gap));
    //初始化s,t
    s0=0,t0=n-1;
    int t=0,maxflow=0;
    gap[0]=n;
    while((t=find_path(s0))>=0) maxflow+=t;
    return maxflow;
}
//并查集判断联通
int fath[point_num];
int find(int x)
{
    return fath[x]==x?x:fath[x]=find(fath[x]);
}
void uion(int x,int y)
{
    x=find(x),y=find(y);
    if(x==y) return ;
    fath[x]=y;
}
//入度+出度 构造网络流模型
int _abs(int x){return x>0?x:-x;}
int in[point_num],out[point_num];
int main()
{
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        memset(cap,0,sizeof(cap));
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=1;i<=point_num;i++) fath[i]=i;//并查集判断联通
        int point ,edge;
        scanf("%d%d",&point,&edge);
        for(int i=0;i<edge;i++)
        {
            int x,y,d;scanf("%d%d%d",&x,&y,&d);//从1开始
            uion(x,y);
            if(d==0) cap[x][y]++;//无向图 添加最大流量为1的流
            in[y]++,out[x]++;//定义x->y;
        }
        int flag=1;
        //判断联通
        int fath1=find(1);
        for(int i=2;i<=point;i++)
        {
            if(find(i)!=fath1)
            {
                flag=0;break;
            }
        }
        //判断入度 出度是否满足条件
        for(int i=1;i<=point;i++)
        {
            if(_abs(in[i]-out[i])%2)
            {
                flag=0;break;
            }
        }
        if(!flag) {printf("impossible\n");continue;}
        //构建网络流模型
        int maxFlow=0;//最大流
        n=point+2;//添加源点0,汇点point+1 总点数为point+2
        for(int i=1;i<=point;i++)
        {
            if(in[i]-out[i]>0) cap[i][n-1]=(in[i]-out[i])/2;
            else if(in[i]-out[i]<0) cap[0][i]=(out[i]-in[i])/2,maxFlow+=cap[0][i];
            else ;
        }
        int cnt=sap();
        if(cnt==maxFlow) printf("possible\n");//如果是满流,则是欧拉回路
        else printf("impossible\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值