HDU 1956 “Sightseeing Tour“ (混合欧拉回路)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1956

引用discuss里的题解思路:
在这里插入图片描述

简单来说就是利用网络流里反向弧的特征来平衡每个点的度,能变向的只有无向边,所以有向边要删除。

以下为dinic算法的AC代码(G++)

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxm = 200 + 5;
const int maxs = 1000 + 5;
int n, m, s, degree[maxm];
int cnt, head[maxs << 1], cur[maxm], depth[maxm];
int start, tend, toCheck[maxs];
int graph[maxm][maxm];

struct edge {
	int to, cap, next;
}e[maxs];

void addedge(int u, int v, int w) {
	e[cnt].to = v;
	e[cnt].cap = w;
	e[cnt].next = head[u];//记录u点之前的最后一条边
	head[u] = cnt++;//记录u的最后一条边
}
bool bfs() {
	memset(depth, -1, sizeof(depth));
	int Thead = 0, Ttail = 0;
	int Q[maxs << 1];//队列
	Q[Ttail++] = start;
	depth[start] = 0;
	while (Thead < Ttail) {
		int u = Q[Thead];
		if (u == tend)return true;
		for (int i = head[u]; i != -1; i = e[i].next) {
			int v = e[i].to;
			if (depth[v] == -1 && e[i].cap > 0) {
				//没有分配层数且仍有容量
				depth[v] = depth[u] + 1;
				Q[Ttail++] = v;
			}
		}
		Thead++;
	}
	return false;
}
int dfs(int u, int cap) {
	if (u == tend)return cap;
	int flow = 0, f;
	for (int& i = cur[u]; i != -1; i = e[i].next) {
		if ((depth[u] + 1 == depth[e[i].to]) && e[i].cap > 0) {
			int f = dfs(e[i].to, min(cap - flow, e[i].cap));
			if (f > 0) {
				e[i].cap -= f;
				e[i ^ 1].cap += f;
				flow += f;
				if (flow == cap)break;
			}
		}
	}
	if (!flow)depth[u] = -2;//防止重搜
	return flow;
}
int main(void) {
	scanf("%d", &n);
	while (n--) {
		scanf("%d %d", &m, &s);
		memset(head, -1, sizeof(head));
		memset(degree, 0, sizeof(degree));
		memset(graph, 0, sizeof(graph));
		start = 0;
		tend = m + 1;
		for (int i = 0; i < s; i++) {
			int x, y, d;
			scanf("%d %d %d", &x, &y, &d);
			degree[x]++;
			degree[y]--;
			if (!d) graph[x][y]++;
		}
		cnt = 0;
		for (int i = 1; i <= m; i++)
			for (int j = 1; j <= m; j++) {
				if (graph[i][j]) {
					addedge(i, j, graph[i][j]);
					addedge(j, i, 0);
				}
			}
		int len = 0;
		bool flag = true;
		for (int i = 1; i <= m; i++)
			if (degree[i] & 1) {
				flag = false;
				break;
			}
		if (!flag) {
			printf("impossible\n");
			continue;
		}
		for (int i = 1; i <= m; i++) {
			if (degree[i] > 0) {
				toCheck[len++] = cnt;
				addedge(start, i, degree[i] / 2);
				addedge(i, start, 0);
			}
			else if (degree[i] < 0) {
				addedge(i, tend, -degree[i] / 2);
				addedge(tend, i, 0);
			}
		}
		while (bfs()) {//tend在层次图中
			for (int i = 0; i <= m + 1; i++)
				cur[i] = head[i];
			while (dfs(start, inf));//找的到增广路
		}
		for (int i = 0; i < len; i++) {
			int u = toCheck[i];
			if (e[u].cap) {
				flag = false;
				break;
			}
		}
		if (flag)printf("possible\n");
		else printf("impossible\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JILIN.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值