HDU 4067 Random Maze 费用流 构造欧拉通路

题目链接:点击打开链接

题意:

给定n个点m条有向边的图, 起点s ,终点t

下面m条边 u,v, a,b  若选择这条边花费为a, 不选择花费为b

构造一条欧拉通路使得起点是s,终点是t,且花费最小。

思路:

首先能想到一个简单的思路:假设所有边都选择,然后在费用流里跑,就会出现负环的问题。。

所以为了避免负环,让所有费用都为正值:

int sum = 0;

若a>b, 则 费用要为正只能是 a-b, 默认这条边是删除是, sum += b, 那么如果我们要选择这条边,则从u=>v, 费用为a-b, 流量为1即可

若a<b, 则费用要为正只能是b-a, 默认这条边是选择是, sum += a, 那么如果我们要删除这条边,则相当于选一条反向的边,即v=>u,费用为b-a, 流量为1

因为我们要保持流量统一,所以用炒鸡汇源来维持,

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
using namespace std;
typedef int ll;
#define inf 0x3f3f3f3f
#define N 300
#define M 605*605*4
struct Edge {
	ll to, cap, cost, nex;
	Edge(){}
	Edge(ll to, ll cap, ll cost, ll next) :to(to), cap(cap), cost(cost), nex(next){}
} edge[M << 1];
ll head[N], edgenum;
ll D[N], A[N], P[N];
bool inq[N];
void add(ll from, ll to, ll cap, ll cost) {
	edge[edgenum] = Edge(to, cap, cost, head[from]);
	head[from] = edgenum++;
	edge[edgenum] = Edge(from, 0, -cost, head[to]);
	head[to] = edgenum++;
}
bool spfa(ll s, ll t, ll &flow, ll &cost) {
	for (ll i = 0; i <= t; i++) D[i] = inf;
	memset(inq, 0, sizeof inq);
	queue<ll>q;
	q.push(s);
	D[s] = 0; A[s] = inf;
	while (!q.empty()) {
		ll u = q.front(); q.pop();
		inq[u] = 0;
		for (ll i = head[u]; ~i; i = edge[i].nex)
		{
			Edge &e = edge[i];
			if (e.cap && D[e.to] > D[u] + e.cost)
			{
				D[e.to] = D[u] + e.cost;
				P[e.to] = i;
				A[e.to] = min(A[u], e.cap);
				if (!inq[e.to])
				{
					inq[e.to] = 1; q.push(e.to);
				}
			}
		}
	}
	//若费用为inf则中止费用流
	if (D[t] == inf) return false;
	cost += D[t] * A[t];
	flow += A[t];
	ll u = t;
	while (u != s) {
		edge[P[u]].cap -= A[t];
		edge[P[u] ^ 1].cap += A[t];
		u = edge[P[u] ^ 1].to;
	}
	return true;
}
ll flow, cost;
ll Mincost(ll s, ll t){
	flow = 0, cost = 0;
	while (spfa(s, t, flow, cost));
	return cost;
}
void init(){ memset(head, -1, sizeof head); edgenum = 0; }

int n, m, s, t, from, to;
int in[N], out[N];
int main(){
	int T, Cas = 1; rd(T);
	while (T--){
		memset(in, 0, sizeof in);
		memset(out, 0, sizeof out);
		init();
		rd(n); rd(m); rd(s); rd(t);
		from = 0, to = n + 1;
		ll now = 0;
		for (int i = 0, u, v, a, b; i < m; i++){
			rd(u); rd(v); rd(a); rd(b);
			if (a > b){
				now += b;
				add(u, v, 1, a - b);
			}
			else {
				now += a;
				add(v, u, 1, b - a);
				in[v]++; out[u]++;
			}
		}
		in[s]++; out[t]++;
		for (int i = 1; i <= n; i++){
			if (in[i] > out[i])
				add(from, i, in[i] - out[i], 0);
			else if (in[i] < out[i])
				add(i, to, out[i] - in[i], 0);
		}
		Mincost(from, to);
		printf("Case %d: ", Cas++);
		for (int i = head[from]; ~i; i = edge[i].nex){
			if (edge[i].cap)flow = -1;
		}
		if (flow == -1)puts("impossible");
		else printf("%d\n", now + cost);
	}
	return 0;
}
时间: 2024-10-01 04:08:42

HDU 4067 Random Maze 费用流 构造欧拉通路的相关文章

HDU 4067 Random Maze 费用流

Random Maze Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1114    Accepted Submission(s): 387 Problem Description In the game "A Chinese Ghost Story", there are many random mazes which h

HDU 4067 Random Maze

题意: 一幅"随机图"定义为有如下性质的图: 有一个入口和一个出口 有向图 对于入口  出度比入度大1 对于出口  入度比出度大1 对于其他点  入度等于出度 现给出一幅有向图  每条边有2个决策--留下.扔掉  分别花费a和b  问  如果用最少的费用改造出"随机图" 思路: 网络流不错的题目  如果做过"混合图欧拉回路"(后文把这个问题成为p)那个zoj的题的话  这道题会有启发 来回忆p的做法  先将无向边随意定向  再利用度来将点划分成二

hdu 4067 Random Maze 最小费用最大流

题意: 给出n个点,m条边,入口s和出口t,对于每条边有两个值a,b,如果保留这条边需要花费:否则,移除这条边需要花费b. 题目要求用最小费用构造一个有向图满足以下条件: 1.只有一个入口和出口 2.所有路都是唯一方向 3.对于入口s,它的出度 = 它的入度 + 1 4.对于出口t,它的入度 = 它的出度 + 1 5.除了s和t外,其他点的入度 = 其出度 最后如果可以构造,输出最小费用:否则输出impossible. 思路: 表示建图太神..给个博客链接:http://www.cppblog.

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

hdu 3315 My Brute 费用流,费用最小且代价最小

很常见的想法了= = #include <stdio.h> #include <iostream> #include <string.h> using namespace std; const int N=400; const int MAXE=200000; const int inf=1<<30; int head[N],s,t,cnt,n,m,ans; int d[N],pre[N]; bool vis[N]; int q[MAXE]; int V[N

HDU 4002 Find the maximum(数论-欧拉函数)

Find the maximum Problem Description Euler's Totient function, φ (n) [sometimes called the phi function], is used to determine the number of numbers less than n which are relatively prime to n . For example, as 1, 2, 4, 5, 7, and 8, are all less than

hdu 3307 Description has only two Sentences (欧拉函数+快速幂)

Description has only two SentencesTime Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 852 Accepted Submission(s): 259 Problem Descriptionan = X*an-1 + Y and Y mod (X-1) = 0.Your task is to calculate th

Play on Words HDU - 1116 (并查集 + 欧拉通路)

Play on Words HDU - 1116 Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. There is a

hdu 1116 Play on Words(欧拉通路)

Problem Description Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. There is a large