poj1637(混合图判欧拉回路)

本文介绍了一种通过网络流模型解决混合图欧拉回路问题的方法。首先将无向边定向,并计算各点的出入度差。若出入度差为偶数,则可通过调整部分边的方向来确保每点出入度相等,从而构成欧拉回路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

把该图的无向边随便定向,计算每个点的入度和出度。如果有某个点出入度
之差为奇数,那么肯定不存在欧拉回路。因为欧拉回路要求每点入度 = 出度,
也就是总度数为偶数,存在奇数度点必不能有欧拉回路。
 好了,现在每个点入度和出度之差均为偶数。那么将这个偶数除以 2,得 x。
也就是说,对于每一个点,只要将 x 条边改变方向(入>出就是变入,出>入就是
9
变出),就能保证出=入。如果每个点都是出=入,那么很明显,该图就存在欧拉
回路。
 现在的问题就变成了:我该改变哪些边,可以让每个点出=入?构造网络流
模型。首先,有向边是不能改变方向的,要之无用,删。一开始不是把无向边定
向了吗?定的是什么向,就把网络构建成什么样,边长容量上限 1。另新建 s 和
t。对于入>出的点 u,连接边(u, t)、容量为 x,对于出>入的点 v,连接边(s, v),
容量为 x(注意对不同的点 x 不同)。之后,察看是否有满流的分配。有就是能
有欧拉回路,没有就是没有。欧拉回路是哪个?察看流值分配,将所有流量非 0
(上限是 1,流值不是 0 就是 1)的边反向,就能得到每点入度=出度的欧拉图。
 由于是满流,所以每个入>出的点,都有 x 条边进来,将这些进来的边反向,
OK,入=出了。对于出>入的点亦然。那么,没和 s、t 连接的点怎么办?和 s 连
接的条件是出>入,和 t 连接的条件是入>出,那么这个既没和 s 也没和 t 连接的
点,自然早在开始就已经满足入=出了。那么在网络流过程中,这些点属于“中
间点”。我们知道中间点流量不允许有累积的,这样,进去多少就出来多少,反
向之后,自然仍保持平衡。

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

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
最大流开始//
typedef int cap_type;
#define MAX_V 500 + 30 + 16

// 用于表示边的结构体(终点、容量、反向边)
struct edge
{
	int to, rev;
	cap_type cap;

	edge(int to, cap_type cap, int rev) : to(to), cap(cap), rev(rev)
	{}
};

vector <edge> G[MAX_V];   // 图的邻接表表示
int level[MAX_V];      // 顶点到源点的距离标号
int iter[MAX_V];       // 当前弧,在其之前的边已经没有用了

// 向图中加入一条从from到to的容量为cap的边
void add_edge(int from, int to, int cap)
{
	G[from].push_back(edge(to, cap, G[to].size()));
	G[to].push_back(edge(from, 0, G[from].size() - 1));
}

// 通过BFS计算从源点出发的距离标号
void bfs(int s)
{
	memset(level, -1, sizeof(level));
	queue<int> que;
	level[s] = 0;
	que.push(s);
	while (!que.empty())
	{
		int v = que.front();
		que.pop();
		for (int i = 0; i < G[v].size(); ++i)
		{
			edge &e = G[v][i];
			if (e.cap > 0 && level[e.to] < 0)
			{
				level[e.to] = level[v] + 1;
				que.push(e.to);
			}
		}
	}
}

// 通过DFS寻找增广路
cap_type dfs(int v, int t, cap_type f)
{
	if (v == t)
	{
		return f;
	}
	for (int &i = iter[v]; i < G[v].size(); ++i)
	{
		edge &e = G[v][i];
		if (e.cap > 0 && level[v] < level[e.to])
		{
			cap_type d = dfs(e.to, t, min(f, e.cap));
			if (d > 0)
			{
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}

	return 0;
}

// 求解从s到t的最大流
cap_type max_flow(int s, int t)
{
	cap_type flow = 0;
	for (;;)
	{
		bfs(s);
		if (level[t] < 0)
		{
			return flow;
		}
		memset(iter, 0, sizeof(iter));
		cap_type f;
		while ((f = dfs(s, t, 0x3f3f3f3f3f3f3f3f)) > 0)
		{
			flow += f;
		}
	}
}
///最大流结束/
vector<int>g[205];
int in[205],out[205];
int main()
{
    int cases,n,m,u,v,w,s,t;
    scanf("%d",&cases);
    while(cases--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++) g[i].clear();
        for(int i=0;i<=300;i++) G[i].clear();
        memset(in,0,sizeof(in)); memset(out,0,sizeof(out));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            in[v]++; out[u] ++;
            if(!w)
            g[u].push_back(v);
        }
        int f = 1;
        for(int i=1;i<=n;i++)
            if(abs(in[i]-out[i])%2!=0)
            { f = 0; break; }
        if(!f) { printf("impossible\n"); continue;}
        s = n+1; t = s+1; int tot = 0;
        for(int i=1;i<=n;i++)
            if(in[i]<out[i]){ add_edge(s,i,(out[i]-in[i])/2); tot += (out[i]-in[i])/2;  }
            else if(in[i]>out[i]){add_edge(i,t,(in[i]-out[i])/2);}
        for(int i=1;i<=n;i++)
        {
            int len = g[i].size();
            for(int k=0;k<len;k++)
            {
                int j = g[i][k];
                add_edge(i,j,1);
            }
        }
        //printf("%d %d\n",max_flow(s,t),tot);
        if(max_flow(s,t)==tot) printf("possible\n");
        else printf("impossible\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值