题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988
题意:给你 个点, 条边,每个点有指定的人和食物的数量。每条边第一次经过不会触碰到电线,从第二次开始,每经过一次都有 的概率碰到,这条边最大允许通过人数是 ,求如何让每个同学都取到食物而且碰到电线的概率最小。
思路:补集思维,求碰到电线概率最小即 不碰到电线概率最大。不碰到电线的概率就是每条边上概率相乘,取个对数就可以转成加法了,然后考虑最小费用最大流建图:设立超级源点 和超级汇点 ,如果该点人数大于食物数,那么源点向这个点连一条容量为人数和食物数之差,费用系数为 的边,否则这个点向汇点连一条人数和食物数之差,费用系数为 的边,然后对于给定的边按条件连就好了,注意要把容量为 的单独拉出来连边,因为第一次走过不会触碰到电线,然后跑下最小费用最大流,再把答案还原回来即可。有个坑是 里面浮点数比较的时候要带上 ,不然会 。
#pragma comment(linker, "/STACK:102400000,102400000")
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r
#define Key_Value ch[ch[root][1]][0]
#define DBN1(a) cerr<<#a<<"="<<(a)<<"\n"
#define DBN2(a,b) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<"\n"
#define DBN3(a,b,c) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<"\n"
#define DBN4(a,b,c,d) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<"\n"
#define DBN5(a,b,c,d,e) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<"\n"
#define DBN6(a,b,c,d,e,f) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<", "<<#c<<"="<<(c)<<", "<<#d<<"="<<(d)<<", "<<#e<<"="<<(e)<<", "<<#f<<"="<<(f)<<"\n"
#define clr(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=10000+5;
const int INF=1e9;
const double eps=1e-8;
const int P=1000000007;
const double PI=acos(-1.0);
template<typename T>
inline T read(T&x){
x=0;int _f=0;char ch=getchar();
while(ch<'0'||ch>'9')_f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x=_f?-x:x;
}
struct Edge{
int from,to,cap,flow;
double cost;
Edge(){}
Edge(int f,int t,int c,int fl,double co):from(f),to(t),cap(c),flow(fl),cost(co){}
};
struct MCMF{
int n,m,s,t,k;
vector<Edge> edges;
vector<int> G[maxn];
bool inq[maxn];
double d[maxn];
int p[maxn];
int a[maxn];
void init(int n,int s,int t){
this->n=n, this->s=s, this->t=t;
edges.clear();
for(int i=0;i<=n;++i) G[i].clear();
}
void AddEdge(int from,int to,int cap,double cost){
edges.push_back(Edge(from,to,cap,0,cost));
edges.push_back(Edge(to,from,0,0,-cost));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool SPFA(int &flow,double &cost){
for(int i=0;i<n;++i) d[i]=INF;
queue<int> Q;
memset(inq,0,sizeof(inq));
d[s]=0, Q.push(s), a[s]=INF, p[s]=0, inq[s]=true;
while(!Q.empty()){
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;i<G[u].size();++i){
Edge &e=edges[G[u][i]];
if(e.cap>e.flow && d[e.to]>d[u]+e.cost+eps){
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i];
a[e.to]=min(a[u],e.cap-e.flow);
if(!inq[e.to]){ Q.push(e.to); inq[e.to]=true; }
}
}
}
if(d[t]==INF) return false;
flow+=a[t];
int u=t;
while(u!=s){
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
cost+=a[t]*edges[p[u]].cost;
u=edges[p[u]].from;
}
return true;
}
double solve(){
int flow=0;
double cost=0;
while(SPFA(flow,cost));
return cost;
}
}MM;
int T,n,m,s,b,u,v,f;
double p;
int main(){
for(scanf("%d",&T);T--;){
scanf("%d%d",&n,&m);
MM.init(n+2,0,n+1);
for(int i=1;i<=n;i++){
scanf("%d%d",&s,&b);
int c=s-b;
if(c>0) MM.AddEdge(0,i,c,0);
else if(c<0) MM.AddEdge(i,n+1,-c,0);
}
for(int i=0;i<m;i++){
scanf("%d%d%d%lf",&u,&v,&f,&p);
p=-log(1.0-p);
if(f>0) MM.AddEdge(u,v,1,0.0);
if(f-1>0) MM.AddEdge(u,v,f-1,p);
}
double ans=MM.solve();
ans=exp(-ans);
printf("%.2f\n",1.0-ans);
}
return 0;
}
Written by Yiming Pan who lives and works in Hangzhou China. Welcome follow me on Github
Cannot load comments. Please check you network.