HDU 4067 Random Maze

题意:

一幅“随机图”定义为有如下性质的图:

有一个入口和一个出口

有向图

对于入口  出度比入度大1

对于出口  入度比出度大1

对于其他点  入度等于出度

现给出一幅有向图  每条边有2个决策——留下、扔掉  分别花费a和b  问  如果用最少的费用改造出“随机图”

思路:

网络流不错的题目  如果做过“混合图欧拉回路”(后文把这个问题成为p)那个zoj的题的话  这道题会有启发

来回忆p的做法  先将无向边随意定向  再利用度来将点划分成二分图  利用无向边建边  利用度连接这些点与源汇  然后做maxflow  满流则有解

“随意定向”启发我们本题也可以对边进行一定的处理  因此我们可以先比较a和b  取其中小的状态  这样得到的一定是费用最小的决策  但不保证是“随机图”  那么此时我们只需要改变决策  在费用最小的情况下达到“随机图”  此时想到了费用流

“利用度构图”启发我们同样讨论  in>out  in==out  in<out  的三种点(其实入口和出口可以稍加处理归并到一般点中去)  对于 in>out 的点  我们与S连边  对于 in<out 的点  我们与T连边  容量即为|in-out|  来表示这个点需要修正的度数

虽然我们的图不是二分图  但是层次关系仍然明显

我们将m条输入的边按照a和b的大小关系  分别建边u->v 容量1 费用b-a 表示将边从留下状态改为扔掉状态  反之亦然

那么此时流量就表示通过更改边的策略  能将多少“度”平衡掉  也就是说  如果maxflow满流  则可以构成“随机图”

剩下的就是最小费用  很明显就是刚才建边的费用之和  最后费用+“随即定向”时的最小花费就是答案

PS:要尽量去理解网络流中“流”的实际意义  想办法构造图

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<cstdlib>
#include<ctime>
#include<cmath>
using namespace std;
typedef long long LL;
#define N 110
#define M 2010
#define inf (1<<20)

int casnum, cas, n, m, s, t, S, T, ans, tot, flow, totflow, cost;
int head[N], pre[N], vis[N], dis[N], din[N], dout[N], temp[N];
struct edge {
	int u, v, w, c, next;
} ed[N * M];
queue<int> qu;

void init() {
	S = 0;
	T = n + 1;
	ans = 0;
	tot = 0;
	totflow = 0;
	flow = 0;
	cost = 0;
	memset(head, -1, sizeof(head));
	memset(din, 0, sizeof(din));
	memset(dout, 0, sizeof(dout));
}

void add(int U, int V, int W, int C) {
	ed[tot].u = U;
	ed[tot].v = V;
	ed[tot].w = W;
	ed[tot].c = C;
	ed[tot].next = head[U];
	head[U] = tot++;

	ed[tot].u = V;
	ed[tot].v = U;
	ed[tot].w = 0;
	ed[tot].c = -C;
	ed[tot].next = head[V];
	head[V] = tot++;
}

int spfa() {
	int i, u, v;
	while (!qu.empty())
		qu.pop();
	for (i = 0; i <= T; i++) {
		vis[i] = 0;
		dis[i] = inf;
		pre[i] = -1;
	}
	qu.push(S);
	vis[S] = 1;
	dis[S] = 0;
	while (!qu.empty()) {
		u = qu.front();
		qu.pop();
		vis[u] = 0;
		for (i = head[u]; ~i; i = ed[i].next) {
			if (!ed[i].w)
				continue;
			v = ed[i].v;
			if (dis[v] > dis[u] + ed[i].c) {
				dis[v] = dis[u] + ed[i].c;
				pre[v] = i;
				if (!vis[v]) {
					vis[v] = 1;
					qu.push(v);
				}
			}
		}
	}
	return dis[T] != inf;
}

void mcmf() {
	int i, tmp;
	while (spfa()) {
		tmp = inf;
		for (i = pre[T]; ~i; i = pre[ed[i].u]) {
			if (tmp > ed[i].w)
				tmp = ed[i].w;
		}
		for (i = pre[T]; ~i; i = pre[ed[i].u]) {
			ed[i].w -= tmp;
			ed[i ^ 1].w += tmp;
			cost += tmp * ed[i].c;
		}
		flow += tmp;
	}
}

struct input {
	int u, v, a, b;
} f[M];

int main() {
	int i, u, v, a, b;
	scanf("%d", &casnum);
	for (cas = 1; cas <= casnum; cas++) {
		scanf("%d%d%d%d", &n, &m, &s, &t);
		init();
		for (i = 1; i <= m; i++) {
			scanf("%d%d%d%d", &u, &v, &a, &b);
			f[i].u = u;
			f[i].v = v;
			f[i].a = a;
			f[i].b = b;
			if (a < b) { //stay
				ans += a;
				din[v]++;
				dout[u]++;
				add(u, v, 1, f[i].b - f[i].a);
			} else {
				ans += b; //remove
				add(v, u, 1, f[i].a - f[i].b);
			}
		}
		for (i = 1; i <= n; i++) {
			temp[i] = dout[i] - din[i];
			if (i == s)
				temp[i]--;
			else if (i == t)
				temp[i]++;
			if (temp[i] > 0) {
				add(S, i, temp[i], 0);
				totflow += temp[i];
			} else if (temp[i] < 0)
				add(i, T, -temp[i], 0);
		}
		mcmf();
		printf("Case %d: ", cas);
		if (totflow == flow)
			printf("%d\n", ans + cost);
		else
			printf("impossible\n");
	}
	return 0;
}
时间: 2024-10-16 14:18:54

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 最小费用最大流

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

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, 费用为

Random Maze (hdu 4067 最小费用流 好题 贪心思想建图)

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

HDU 4035:Maze 概率DP求期望(有环)

Maze 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4035 题意: 有N(2 ≤ N ≤ 10000)个房间和一堆双向边(不存在环),每个房间有ki和ei两个值,分别代表回到房间1和游戏结束的概率,求游戏结束时通过的边数的期望 题解: 一道很好很经典的求期望的题 设E[i]为以i为起点,直到游戏结束所通过边数的期望,则E[1]即所求答案 设fa代表父亲节点(由于不存在环,则图为一棵树,设1为根节点),∑ch代表所有孩子节点,size代表与这

HDU 4035:Maze(概率DP)

http://acm.split.hdu.edu.cn/showproblem.php?pid=4035 Maze Special Judge Problem Description When wake up, lxhgww find himself in a huge maze. The maze consisted by N rooms and tunnels connecting these rooms. Each pair of rooms is connected by one and

【HDU】4035 Maze

http://acm.hdu.edu.cn/showproblem.php?pid=4035 题意:给一棵n个节点的树,每个节点有值k[i]和e[i],分别表示k[i]概率走向1号节点,e[i]概率获得胜利(即停止),如果没有进行上边任意操作,则等概率的走向与这个节点连边的点.问走过的边的期望.(n<=10000) #include <cstdio> #include <cstring> using namespace std; const int N=10005; cons

HDU4067 Random Maze(最小费用最大流)

题目大概说,给一张图,删除其中一些单向边,使起点s出度比入度多1,终点t入度比出度多1,其他点出度等于入度.其中删除边的费用是bi,保留边的费用是ai,问完成要求最小的费用是多少. 一开始我想到和混合图欧拉回路(POJ1637)的类似构造方法: 假设所有边一开始都是保留的,算出各个点的入度和出度,另外s点的出度-1,t点的入度-1: 然后把出度-入度等于正数的点源点向其连一条容量为出度-入度的边,等于负数的点其向汇点连一条容量为入度-出度的边 这样就是要通过删除边使那些与源汇相连的边满流,这样就

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i