HDU5988 Coding Contest 【最小费用最大流】【2016ACM/ICPC亚洲区青岛站】

题意:

给出n个点和m条边,每个点有si个人,bi份食物,每条边一开始可以通过一个人,后来的人每通过一个就有pi的概率使整个系统崩溃,问崩溃的最小的概率是多少

思路:

对于崩溃的最小概率,由于只有一条奔溃就会全部崩溃,那么将所有不会崩溃的概率相乘就是不会奔溃的概率,所以崩溃的概率 = 1 - 不会崩溃的概率,所以要求最大不会崩溃的概率,那么我们只要对不会崩溃的概率取反即可
一开始想到了网络流,但是对于概率相乘不知道如何处理,然后学到了一个公式:
l o g ( a ) + l o g ( b ) + l o g ( c ) = = l o g ( a b c ) log(a) + log(b) + log(c) == log(a*b*c) log(a)+log(b)+log(c)==log(abc)
所以费用为 l o g ( 1 p i ) -log(1-p_{i}) log(1pi)
由于点从1到n,于是我们可以建立一个以0为源点,以n+1为汇点的图。
每个区域如果有食物和人,那么人先吃掉食物是最优的。
如果食物过量的点,我们可以建一条边从源点到该点,容量是过量的食物数量,费用是0;
如果人数过量的点,我们可以建一条边从该点到汇点,容量是过量的人数,费用是0。
剩下的就是图中的m条边,对于每条边分解成两条边,为:
从u到v,容量是1,费用是0;从u到v,容量是cap-1,费用为 l o g ( 1 p i ) -log(1-p_{i}) log(1pi)
据此,跑一遍最小费用最大流即可

我用的是kuangbin的SPFA的模板,一开始T了一发,不会图论,想不明白为什么会T
于是套了zkw费用流板子

AC_code:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int MAXM = 20000;
const int INF = 0x3f3f3f3f;
struct Edge {
	int to,next,cap,flow;
	double cost;
	Edge(int _to = 0,int _next = 0,int _cap = 0,int _flow = 0,double _cost = 0):
		to(_to),next(_next),cap(_cap),flow(_flow),cost(_cost) {}
} edge[MAXM];
struct ZKW_MinCostMaxFlow {
	int head[MAXN],tot;
	int cur[MAXN];
	double dis[MAXN];
	bool vis[MAXN];
	int ss,tt,N;//源点、汇点和点的总个数(编号是 0~N-1), 不需要额外赋值,调用会直接赋值
	int  max_flow;
	double min_cost;
	void init() {
		tot = 0;
		memset(head, -1,sizeof(head));
	}
	void addedge(int u,int v,int cap,double cost) {
		edge[tot] = Edge(v,head[u],cap,0,cost);
		head[u] = tot++;
		edge[tot] = Edge(u,head[v],0,0, -cost);
		head[v] = tot++;
	}
	int aug(int u,int flow) {
		if(u == tt)return flow;
		vis[u] = true;
		for(int i = cur[u]; i != -1; i = edge[i].next) {
			int v = edge[i].to;
			if(edge[i].cap > edge[i].flow && !vis[v] && dis[u] ==dis[v] + edge[i].cost) {
				int tmp = aug(v,min(flow,edge[i].cap - edge[i].flow));
				edge[i].flow += tmp;
				edge[i^1].flow -= tmp;
				cur[u] = i;
				if(tmp)return tmp;
			}
		}
		return 0;
	}
	bool modify_label() {
		double d = INF;
		for(int u = 0; u < N; u++)
			if(vis[u])
				for(int i = head[u]; i != -1; i = edge[i].next) {
					int v = edge[i].to;
					if(edge[i].cap>edge[i].flow && !vis[v])
						d = min(d, dis[v]+edge[i].cost - dis[u]);
				}
		if(d == INF)return false;
		for(int i = 0; i < N; i++)
			if(vis[i]) {
				vis[i] = false;
				dis[i] += d;
			}
		return true;
	}
	/* * 直接调用获取最小费用和最大流 * 输入: start-源点,end-汇点,n-点的总个数(编号从 0 开始) * 返回值: pair<int,int> 第一个是最小费用,第二个是最大流 */
	pair<double,int> mincostmaxflow(int start,int end,int n) {
		ss = start, tt = end, N = n;
		min_cost = max_flow = 0;
		for(int i = 0; i < n; i++)dis[i] = 0;
		while(1) {
			for(int i = 0; i < n; i++)cur[i] = head[i];
			while(1) {
				for(int i = 0; i < n; i++)vis[i] = false;
				int tmp = aug(ss,INF);
				if(tmp == 0)break;
				max_flow += tmp;
				min_cost += tmp*dis[ss];
			}
			if(!modify_label())break;
		}
		return make_pair(min_cost,max_flow);
	}
} solve;

int main() {
	int t, n, m, a, b, u, v, cap;
	double cost;
	scanf("%d", &t);
	while(t--)	{
		scanf("%d %d", &n, &m);
		solve.init();//n个点 + 源点0 + 汇点 n+1
		for(int i = 1; i <= n; i++) {
			scanf("%d %d", &a, &b);
			a -= min(a, b);
			b -= min(a, b);
			if(a > 0) {
				solve.addedge(0, i, a, 0);
			} else {
				solve.addedge(i, n+1, b, 0);
			}
		}
		for(int i = 1; i <= m; i++) {
			scanf("%d %d %d %lf", &u, &v, &cap, &cost);
			if(cap > 0) {
				solve.addedge(u, v, 1, 0);
			}
			if(cap-1 > 0) {
				solve.addedge(u, v, cap-1, -1*log(1.0-cost));
			}
		}
		pair<double, int> ans = solve.mincostmaxflow(0, n+1, n+1);
		double q = ans.first;
		q = 1.0 - exp(-1.0*q);
		printf("%.2lf\n", q);
	}

	return 0;
}
全部评论

相关推荐

06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务