hdu 5988 Coding Contest (费用流变形)
来源:互联网 发布:中国农大远程网络教育 编辑:程序博客网 时间:2024/06/05 20:52
题意:给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭。每个点有S个人,有B盒饭。每条边只能被走c次,每条边上都有电线,第一个人通过的时候,不会破坏电线,从第二个人开始,每次都有概率p破坏掉电线。使得每个人都能吃饭,求最小破坏电线的概率。
解法:每条边有走的次数(流量),每条边走一次发生破坏概率为p(流量1,费用p),容易想到费用流。可是费用流往往是费用相加的,这个是概率,只能相乘。有什么办法,log函数可以把乘除法转换为加减法。所以对每个概率取个log当成费用就行了。
log取底数取个2,然后对每条边的概率值取个对数,跑一次最小费用流,感觉没什么问题,但是会wa,因为概率总是小于1的,而底数是2,这样取log后会变为负数。费用为负,跑出来的费用就会朝更小走,在这个题上会出问题。那么取个负呢,把负变成正,还是会出问题,取负之后最小就变成了最大,跑出来是最大费用,也是会出问题的。
这时候就应该从反方向进行考虑,求踩坏的最小概率,就是求不踩坏的最大概率,1-p后取log,和以上同理,求出了最大费用。取出来还回去后用1减一下就好了。
新建源点s,汇点t,对于S>B的需要人走,从源点连一条流量为S[i]-B[i],费用为0(出门不需要费用)的边过去,add(s,i,S[i]-B[i],0),对于s<b的,add(i,t,B[i]-S[i],0)。
然后还有一个问题,就是第一次踩的时候,不会触发,那么从原有的边中取一条出来,流量1,费用0就好了。
------------------------------------------***********************************-----------------------------
然而我的模板很是垃圾,一个点到另一个点不能有多条边,然后GG,所以找了别人能过得一份代码当作我的模板
#include<cstdio>#include<string.h>#include<queue>#include<algorithm>#define maxm 50000#define inf 1e8using namespace std;const int maxn = 200;const double eps = 1e-7;const float EXP = exp(1.0);int num, p[maxn]; ///邻接表头结点struct EDGE{ int u, v, flow, next; double cost; EDGE() {} EDGE(int u, int v, int flow,double cost, int next): u(u), v(v), flow(flow),cost(cost), next(next) {}} E[maxm];int n,m;int S[maxn],B[maxn]; ///每个点的人数S,饭Bvoid init() ///初始化{ num = 0; memset(p, -1, sizeof p);}void add(int u, int v, int flow, double cost){ E[num] = EDGE(u, v, flow, cost, p[u]); p[u] = num++; E[num] = EDGE(v, u, 0, -cost, p[v]); p[v] = num++;}int pre[maxn], mi[maxn];double dis[maxn];bool inq[maxn];int s, t; ///源点汇点double ans;int flow;int que[maxn];bool spfa() { for(int i = 0; i <=t; i++) inq[i] = 0, dis[i] = inf,pre[i]=-1; dis[s] = 0, mi[s] = inf, inq[s] = 1; int l = 0, r = 1; que[l] = s; while(l != r) { int u = que[l++]; if(l == maxn) l =0; inq[u] = 0; for(int i = p[u]; i + 1; i = E[i].next) { int v = E[i].v; if(E[i].flow && dis[v] > dis[u] + E[i].cost+eps) { dis[v] = dis[u] + E[i].cost; pre[v] = i; mi[v] = min(mi[u], E[i].flow); if(!inq[v]) { inq[v] = 1; que[r++] = v; if(r >= maxn) r -= maxn; } } } } if(pre[t]==-1) return false; flow += mi[t]; ans += mi[t] * dis[t]; int u = t; for(int i = pre[u]; i + 1; i = pre[E[i].u]) { E[i].flow -= mi[t]; E[i ^ 1].flow += mi[t]; } return true;}double Mincost(){ ans = 0, flow = 0; while(spfa()); return ans;}int main(void){ int T; scanf("%d",&T); while(T--){ init(); scanf("%d%d",&n,&m); s = 105,t = 106; for(int i = 1;i <= n;i++){ scanf("%d%d",&S[i],&B[i]); if(S[i] > B[i]){ ///人数大于饭数,源点建边出来 add(s,i,S[i]-B[i],0); } if(B[i] > S[i]){ ///人数小于饭数,建边到汇点 add(i,t,B[i]-S[i],0); } } for(int i = 1;i <= m;i++){ int u,v,f; double pp; scanf("%d%d%d%lf",&u,&v,&f,&pp); add(u,v,1,0); ///第一次走没有费用 add(u,v,f-1,-log2(1-pp)); ///流量-1 } double tmp = Mincost(); printf("%.2f\n",1-pow(2,-tmp)); } return 0;}
- hdu 5988 Coding Contest (费用流变形)
- HDU 5988 Coding Contest 最小费用流变形
- hdu 5988 Coding Contest (费用流)
- HDU 5988 Coding Contest(费用流)
- 【HDU 5988】 Coding Contest 【费用流】
- HDU-5988-Coding Contest(费用流)
- hdu 5988 Coding Contest (最小费用流)
- HDU-5988 Coding Contest 最大费用流
- hdu 5988 Coding Contest 费用流
- HDU 5988 Coding Contest(费用流)
- HDU 5988 Coding Contest(最小费用最大流)
- [最大费用最大流]HDU 5988 Coding Contest
- hdu 5988 Coding Contest(最小费用流 骚)
- HDU 5988 Coding Contest (最小费用流)
- HDU-5988 Coding Contest
- HDU 6118 度度熊的交易计划 (最小费用流变形)
- hdu 5988 Coding Contest 青岛G题 费用流以及一些感想吧
- HDU 5988 Coding Contest 2016青岛G题浮点费用流
- 在C++中如何将二维数组作为函数参数
- 泛型笔记
- QT读写配置文件(.ini)
- 函数循环中return_break_continue
- win7下利用DockerToolBox安装Docker步骤
- hdu 5988 Coding Contest (费用流变形)
- java匿名内部类
- 【离线+并查集按秩合并】UOJ14(UER #1)[DZY Loves Graph]题解
- 人生第一篇博客(关于C语言的学习)
- android studio 取消默认快速安装(取消默认选中安装设备)
- java基础知识 equals和==
- SDUT 2040 数据结构上机实验之顺序查找
- Weblogic java生成wlfullclient.jar
- 礼物分配 (差分约束)