题目链接:Coding Contest - HDU 5988 - Virtual Judge
Coding Contest
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 7618 Accepted Submission(s): 1785
For the i-th path, the wires have been stabilized at first and the first competitor who walker through it would not break the wires. Since then, however, when a person go through the i - th path, there is a chance of $p_i$ to touch
the wires and affect the whole networks. Moreover, to protect these wires, no more than $c_i$ competitors are allowed to walk through the i-th path.
Now you need to find a way for all competitors to get their lunch, and minimize the possibility of network crashing.
For each test case, the first line consists of two integers N (N ≤ 100) and M (M ≤ 5000). Each of the next N lines contains two integers si and $b_i$ ($s_i$ , $b_i$ ≤ 200).
Each of the next M lines contains three integers $u_i$ , $v_i$ and $c_i(c_i$ ≤ 100) and a float-point number $p_i$(0 < $p_i$ < 1).
It is guaranteed that there is at least one way to let every competitor has lunch.
1 4 4 2 0 0 3 3 0 0 3 1 2 5 0.5 3 2 5 0.5 1 4 5 0.5 3 4 5 0.5
分析
首先要想到这是个网络流问题。
已知每条边失败率为 p i p_i pi,则最小失败率应该是形如 p 1 ∗ p 2 ∗ . . . p_1*p_2*... p1∗p2∗...。因为最小费网络流只能计算加法,故取对数,式子转换为 e l n ( p 1 ) + l n ( p 2 ) + . . . e^{ln(p_1)+ln(p_2)+...} eln(p1)+ln(p2)+...。其中 l n ( p i ) ln(p_i) ln(pi)似乎可以作为每条边的费用,但 p i p_i pi小于1时 l n ( p i ) ln(p_i) ln(pi)小于0。尝试加符号变为 − l n ( p i ) -ln(p_i) −ln(pi),又变成了个减函数,失败率越高费用反而越小。换个角度,尝试以成功率 1 − p i 1-p_i 1−pi建模,则 − l n ( 1 − p i ) -ln(1-p_i) −ln(1−pi)表示随成功率升高,费用越来越低,符合网络流求最小费的基本原理。此时的最小费形如 m i n c o s t = − l n ( 1 − p 1 ) − l n ( 1 − p 2 ) − . . . mincost=-ln(1-p_1)-ln(1-p_2)-... mincost=−ln(1−p1)−ln(1−p2)−...,此时的 e l n ( p 1 ) + l n ( p 2 ) + . . . e^{ln(p_1)+ln(p_2)+...} eln(p1)+ln(p2)+...则等于最大的成功率。最小失败率则等于1-最大成功率。
然后需要一个能处理浮点数的网络流,我的板子在这直接TLE了,赛后临摹大牛的才整好的。
#include <bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxv=1e2+10; //max vertex
const double eps=1e-8;
double mcost;
struct edge{
int to,cap,rev;
double cost;
};
vector<edge> G[maxv];
bool vis[maxv];
double dist[maxv];
void init(){
mcost=0;
for(int i=0;i<maxv;i++) G[i].clear();
}
void add_edge(int from, int to, int cap, double cost){
G[from].push_back(edge{to,cap,(int)G[to].size(),cost});
G[to].push_back(edge{from,0,(int)G[from].size()-1,-cost});
}
bool spfa(int s,int t){
memset(vis,false,sizeof(vis));
for(int i=0;i<maxv;i++) dist[i]=INF;
dist[s]=0;
queue<int> q;
q.push(s); vis[s]=true;
while(!q.empty()){
int u=q.front(); q.pop();
for(auto &e : G[u]){
if(e.cap>0 && dist[e.to]>dist[u]+e.cost+eps){
dist[e.to]=dist[u]+e.cost;
if(!vis[e.to]){
vis[e.to]=true;
q.push(e.to);
}
}
}
vis[u]=false;
}
return dist[t]<INF-eps;
}
int dfs(int v,int t,int f){
vis[v]=true;
if(v==t) return f;
int ret=0;
for(auto &e:G[v]){
if(!vis[e.to] && e.cap>0 && fabs(dist[v]+e.cost-dist[e.to])<eps){
int d=dfs(e.to, t, min(e.cap, f-ret));
if(d){
mcost+=e.cost*d;
e.cap-=d;
G[e.to][e.rev].cap+=d;
ret+=d;
if(ret==f) break;
}
}
}
return ret;
}
int costflow(int s,int t){
int flow=0;
while(spfa(s,t)){
vis[t]=true;
while(vis[t]){
memset(vis,false,sizeof(vis));
flow+=dfs(s,t,INF);
}
}
return flow;
}
const int SUPER_SRC=105;
const int SUPER_DST=SUPER_SRC+1;
void solve(){
init();
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
int s,b;
cin>>s>>b;
add_edge(SUPER_SRC,i,s,0);
add_edge(i,SUPER_DST,b,0);
}
while(m--){
int u,v,cap;
double w;
cin>>u>>v>>cap>>w;
w=-log(1.0-w);
swap(u,v);
add_edge(u,v,cap-1,w);
add_edge(u,v,1,0);
}
costflow(SUPER_SRC,SUPER_DST);
printf("%.2lf\n",1.0-pow(exp(1.0),-mcost));
}
int main(){
ios::sync_with_stdio(0);
int T;
cin>>T;
while(T--){
solve();
}
return 0;
}