题意:在n个点上有着食物,有m条边,除了第一个走的人,其他人都有pi的概率这条边,再大家都能获得食物的前提下,求破坏网络的概率最小。
思路:
每条边有走的次数(流量),每条边走一次发生破坏概率为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就好了。(来源网络,写的炒鸡棒)
#include<iostream> #include<cstdio> #include<string.h> #include<cmath> #include<queue> //#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PI; typedef pair< PI, int> PII; #define pb push_back #define Key_value ch[ch[root][1]][0] #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define MS(x,y) memset(x,y,sizeof(x)) const double eps=1e-10; const double pi=acos(-1.0); const int mod=1e9+7; const int INF=0x3f3f3f3f; const int M = 1000100; const int MAXN = 10010; const int MAXM = 100050; struct Edge { int to,next,cap,flow; double cost; } edge[MAXM]; int head[MAXN],tol; int pre[MAXN]; double dis[MAXN]; bool vis[MAXN]; int N; void init(int n) { N = n; tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,double cost) { edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s,int t) { queue<int>q; for(int i = 0; i <= N; i++) { dis[i] = INF; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dis[v] - dis[u] - edge[i].cost >eps) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t] == -1)return false; else return true; } int minCostMaxflow(int s,int t,double &cost) { int flow = 0; cost = 0; while(spfa(s,t)) { int Min = INF; for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; } for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; cost += edge[i].cost * Min; } flow += Min; } return flow; } int main() { int t; scanf("%d",&t); while(t--) { int n,m; scanf("%d%d",&n,&m); init(n+1); int s=0,t=n+1; for(int i=1; i<=n; ++i) { int a,b; scanf("%d%d",&a,&b); if(a!=0) addedge(s,i,a,0.0); if(b!=0) addedge(i,t,b,0.0); } int u,v,c; double p; for(int i=0; i<m; ++i) { scanf("%d%d%d%lf",&u,&v,&c,&p); p=-log(1-p); //log2() addedge(u,v,c-1,p); addedge(u,v,1,0.0); } double ans; minCostMaxflow(s,t,ans); printf("%.2lf\n",1-exp(-ans)); } return 0; }
然而跑了900多ms,已经想不到让时间降下去的姿势了。。
- 版权声明:本文基于《知识共享署名-相同方式共享 3.0 中国大陆许可协议》发布,转载请遵循本协议
- 文章链接:http://www.carlstedt.cn/archives/1319 (转载时请注明本文出处及文章链接)
发表评论
快来吐槽一下吧!