Coding Contest

题意:HDU 5988 Coding Contest(最小费用最大流)_#ifndef个区域,每个区域有一些食物和人,HDU 5988 Coding Contest(最小费用最大流)_最小费用最大流_02条有向路径,每条路径有人数上限,第一个通过的人不会触电,之后通过的人有HDU 5988 Coding Contest(最小费用最大流)_#include_03的概率触电,求所有人都获取到食物触电的最小概率。

题解:转换为求不会触电的最大概率。但是呢,我们在费用流里都是通过相加得到的结果,所以有没有将乘法变为加法的方法呢?没错,就是HDU 5988 Coding Contest(最小费用最大流)_#include_04,取个log就变成了加法。对于HDU 5988 Coding Contest(最小费用最大流)_#ifndef_05HDU 5988 Coding Contest(最小费用最大流)_#ifndef_06,首先连一条费用为HDU 5988 Coding Contest(最小费用最大流)_c++_07流量为HDU 5988 Coding Contest(最小费用最大流)_hdu5988_08的边,再连一条费用为HDU 5988 Coding Contest(最小费用最大流)_最小费用最大流_09流量为HDU 5988 Coding Contest(最小费用最大流)_#ifndef_10的边。最后令源点连向人多余的点,食物多余的点向汇点连边。然后最后取得答案再转换回来即可。

代码

#include<bits/stdc++.h>
const int N = 21010, inf = 2e9;
using namespace std;
int n,m,s[200],b[200];
struct Edge{
int to,nxt,cap,flow;
double cost;
Edge() {}
Edge(int x,int y,int z,int p,double s) : to(x),nxt(y),cap(z),flow(p),cost(s) {}
}edge[N];
int head[200],pre[200],tot;
double dis[200];
bool vis[N];

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++;
}

bool spfa(int s,int t) {
queue<int> q;
memset(vis, 0, sizeof vis);
memset(pre, -1, sizeof pre);
for(int i = s; i <= t; ++i) dis[i] = inf;
dis[s] = 0;
vis[s] = 1;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(edge[i].cap > edge[i].flow && dis[v] - dis[u] - edge[i].cost > 1e-8) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if(!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
}
if(pre[t] == -1) return 0;
return 1;
}

void mcmf(int s,int t,double &cost) {
int flow = 0;
while(spfa(s,t)) {
int min1 = inf;
for(int i = pre[t]; ~i; i = pre[edge[i^1].to]) {
if(min1 > edge[i].cap - edge[i].flow)
min1 = edge[i].cap - edge[i].flow;
}
for(int i = pre[t]; ~i; i = pre[edge[i^1].to]) {
edge[i].flow += min1;
edge[i ^ 1].flow -= min1;
cost += edge[i].cost * min1;
}
flow += min1;
}
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in","r",stdin);
#endif
int T,c,u,v; double p;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
init();
for(int i = 1; i <= n; ++i){
scanf("%d%d",&s[i],&b[i]);
if(s[i] > b[i]) {
addEdge(0,i,s[i] - b[i],0);
}else{addEdge(i,n + 1,b[i] - s[i],0);
}
}
for(int i = 1; i <= m; ++i){
scanf("%d%d%d%lf",&u,&v,&c,&p);
addEdge(u,v,c-1,-log2(1.0-p));
addEdge(u,v,1,0);
}
double cost = 0;
mcmf(0,n + 1,cost);
printf("%.2f\n",1.0 - pow(2,-cost));
}

return 0;
}