UVA 10746 Crime Wave – The Sequel(费用流)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1687

ProblemG

CrimeWave – The Sequel

Input: StandardInput

Output: StandardOutput

TimeLimit: 2
Seconds

n bankshave been robbed this fine day. (greater than orequal to n)
police cruisers are on duty at variouslocations in the city. n of the cruisers should bedispatched, one to each of the banks, so as to minimize the averagetime of arrival at the n banks.

Input

Theinput file contains several sets of inputs. The description of eachset is given below:

Thefirst line of input contains 0 < n <= m <=20n lines follow, each containing m positivereal
numbers: the travel time for cruiser m to reachbank n.

Inputis terminated by a case where m=n=0. This case should notbe processed.

Output

Foreach set of input output a single number: the minimum average traveltime, accurate to 2 fractional
digits.

 

SampleInput                             Outputfor Sample Input

3 4
10.0 23.0 30.0 40.0
5.0 20.0 10.0 60.0
18.0 20.0 20.0 30.0

00


13.33



Problemsetter: GordonCormack, EPS

题意:

有m个警察,派n个警察到n个银行,给出每个警察到各银行的时间,求最小的平均时间。

分析:

平均乘上n就是总时间,也就是要最小化总时间,那么用费用流就可以解决问题。各银行向每个警察连边,容量1,费用为时间;增加源点,源点向各银行连边,容量1,费用0;增加汇点,警察向汇点连边,容量1,费用0。在图中跑费用流就行。

这题最恶心的地方在于保留小数,结果加上eps再输出。这里涉及到保留小数方法,是用传统的四舍五入还是用银行家舍入?都不知道以后涉及到小数的输出要怎么搞了,这种东西就该spj啊。

/*
 *
 *	Author	:	fcbruce
 *
 *	Date	:	2014-09-05 20:37:26
 *
 */
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10

#ifdef _WIN32
	#define lld "%I64d"
#else
	#define lld "%lld"
#endif

#define maxm 2333
#define maxn 64

using namespace std;

int fir[maxn];
int u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm];
double cost[maxm];
int e_max;
double d[maxn];
int p[maxn];
bool inq[maxn];
int q[maxm<<3];

inline void add_edge(int _u,int _v,int _cap,double _cost)
{
	int e;
	e=e_max++;
	u[e]=_u;v[e]=_v;cap[e]=_cap;cost[e]=_cost;
	nex[e]=fir[u[e]];fir[u[e]]=e;
	e=e_max++;
	u[e]=_v;v[e]=_u;cap[e]=0;cost[e]=-_cost;
	nex[e]=fir[u[e]];fir[u[e]]=e;
}

void SPFA(int s)
{
	memset(inq,0,sizeof inq);
	memset(d,0x7f,sizeof d);
	int f,r;
	d[s]=0;
	q[f=r=0]=s;
	while (f<=r)
	{
		int x=q[f++];
		inq[x]=false;
		for (int e=fir[x];~e;e=nex[e])
		{
			if (cap[e]>flow[e] && d[v[e]]>d[u[e]]+cost[e]+eps)
			{
				d[v[e]]=d[u[e]]+cost[e];
				p[v[e]]=e;
				if (!inq[v[e]])
				{
					inq[v[e]]=true;
					q[++r]=v[e];
				}
			}
		}
	}
}

pair<double,int> min_cost_flow(int s,int t)
{
	memset(flow,0,sizeof flow);
	double total_cost=0;
	int total_flow=0;

	for (;;)
	{
		SPFA(s);

		if (d[t]>INF)	break;

		int _f=INF;
		for (int e=p[t];;e=p[u[e]])
		{
			_f=min(_f,cap[e]-flow[e]);
			if (u[e]==s)	break;
		}

		for (int e=p[t];;e=p[u[e]])
		{
			flow[e]+=_f;
			flow[e^1]-=_f;
			if (u[e]==s)	break;
		}

		total_cost+=d[t]*_f;
		total_flow+=_f;
	}

	return make_pair(total_cost,total_flow);
}

int main()
{
#ifdef FCBRUCE
	freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE

	int n,m;

	while (scanf( "%d%d",&n,&m),n||m)
	{
		int s=0,t=n+m+1;

		e_max=0;
		memset(fir,-1,sizeof fir);

		double w;
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=m;j++)
			{
				scanf( "%lf",&w);
				add_edge(i,n+j,1,w);
			}
		}

		for (int i=1;i<=n;i++)
			add_edge(s,i,1,0);

		for (int j=1;j<=m;j++)
			add_edge(j+n,t,1,0);

		auto res=min_cost_flow(s,t);

		printf( "%.2f\n",res.first/res.second+eps);
	}

	return 0;
}
时间: 2024-10-10 02:46:45

UVA 10746 Crime Wave – The Sequel(费用流)的相关文章

UVA 10746 Crime Wave - The Sequel【最小费用最大流】

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1687 题意:给你n个城市到m个海港的距离,求每个城市都有船只去的最短平均航行距离. 源点向城市建边 城市向海港 海港向汇点建边 容量为1,最后城市向海港的费用为距离 代码: #include<stdio.h> #include<iostream> #in

uva 10746 Crime Wave - The Sequel(最小费用流)

题目: 链接:点击打开链接 题意: 一天n个银行被抢了,m个值班的警车在不同的位置,n个这样的警车应该被派往每个银行,以便平均到达n个银行的时间最少. 思路: 尽管题目很裸,还是不会做,看来还是差很多啊,. 单源,源点s=0,汇点t=n+m+1.警车编号1到m.银行编号m+1到n+m+1. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <queue> using n

UVa 12534 Binary Matrix 2 zkw费用流模版题

题目链接:点击打开链接 思路: 我们首先假设这个图都是全0的 用n个点代表行,m个点代表列 用源点向行连一个值x 表示每行1的个数,向列连一个y表示每列y个1 则若行i和列j之间流过一个流量就表示 (i,j) 点填了1 那么若原来图中(i,j)点为0 则花费就是1 若原图中(i,j)点是1,则花费是-1 如此枚举x跑个费用流就好了 ==居然把我多年的白书费用流坑掉了... zkw走起啊 #include <stdio.h> #include <string.h> #include

UVa 2197 &amp; 拆点分环费用流

题意: 给你一个带权有向图,选择一些边组成许多没有公共边的环,使每个点都在k个环上,要求代价最小. SOL: 现在已经养成了这种习惯,偏题怪题都往网络流上想... 怎么做这题呢... 对我们看到每个点都在k个环上,而且没有公共边,那么很显然每个点的入度出度都为k.   然后我们拆点,建源汇ST,S与每个入点连边容量为k,出点与汇点相连容量为k,费用为0,如果城市i,j之间有边那么将i的入点和j的出点连一条费用为权,容量为1的边.然后跑一遍费用流.如果每条边都满流那么就有解. 好神奇...从环变成

【网络流24题】No.19 负载平衡问题 (费用流)

[题意] G 公司有 n 个沿铁路运输线环形排列的仓库, 每个仓库存储的货物数量不等. 如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入文件示例input.txt517 9 14 16 4 输出文件示例output.txt11 [分析] 其实我觉得这题可以贪心啊..n^2贪心??.没细想.. 打的是费用流.. 大概这样建图: 懒得写了..凌乱之美.. 求满流费用.. 1 #include<cstdio> 2 #include<cstdlib&

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

hdu 2448 Mining Station on the Sea【网络费用流】

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 732 Problem Description The ocean is a treasure house of resources and the development

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

uva 1478 - Delta Wave(递推+大数+卡特兰数+组合数学)

题目链接:uva 1478 - Delta Wave 题目大意:对于每个位置来说,可以向上,水平,向下,坐标不能位负,每次上下移动最多为1, 给定n问说有多少种不同的图.结果对10100取模. 解题思路:因为最后都要落回y=0的位置,所以上升的次数和下降的次数是相同的,并且上升下降的关系满足出栈入栈的关系.即卡特兰数. 所以每次枚举i,表示有i个上升,i个下降,用组合数学枚举出位置,然后累加求和. C(2?in)?f(i)=C(2?i?2n)?f(i?1)?(n?2?i+1)?(n?2?i+2)