HDU 5988 Coding Contest(费用流+浮点数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988

题目大意:

给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭。每个点有S个人,有B盒饭。每条边只能被走c次,每条边上都有电线,
第一个人通过的时候,不会破坏电线,从第二个人开始,每次都有概率p破坏掉电线。使得每个人都能吃饭,求最小破坏电线的概率。

解题思路:

题目要求我们求最小破坏电线的概率,就是一个最小乘积问题,加上log可以将其转变为加法,那样就可以使用费用刘来解决了。

按以下方式建图:

①源点st向第i个人建边,流量为S。

②第i个人向汇点建边,流量为B。

③u->v连边,流量为c,花费为-log(1-p)。

然后跑费用流,1-exp(-cost)即为答案。

代码

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #include<vector>
  8 #define LL long long
  9 #define pii pair<double,int>
 10 #define pll pair<long long,long long>
 11 #define rep(i,a,b) for(int i=a;i<=b;i++)
 12 #define per(i,a,b) for(int i=a;i>=b;i--)
 13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
 14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl;
 15 #define bugc(_) cout << (#_) << " = " << (_) << endl;
 16 using namespace std;
 17 const double eps=1e-8;
 18 const int N=1e2+5;
 19 const int M=1e5+5;
 20 const int INF=0x3f3f3f3f;
 21 
 22 struct node{
 23     int to,next,flow;
 24     double cost;
 25 }edge[M*2]; 
 26 
 27 int cnt,st,en,n,m;
 28 int head[N],pre[N];
 29 double dis[N];//dis[i]表示到dis[i]为止不破坏电线的最大概率
 30 bool vis[N];
 31 
 32 int sgn(double x) { return x < -eps? -1: x > eps; }
 33 
 34 void init(){
 35     cnt=2;
 36     memset(head,0,sizeof(head));
 37 } 
 38 
 39 void link(int u,int v,int flow,double cost){
 40     edge[cnt]=node{v,head[u],flow,cost};
 41     head[u]=cnt++;
 42     edge[cnt]=node{u,head[v],0,-cost};
 43     head[v]=cnt++;
 44 }
 45 
 46 bool spfa() {
 47     memset(pre,0,sizeof(pre));
 48     memset(vis,false,sizeof(vis));
 49     for(int i=st;i<=en;i++) dis[i]=INF;
 50     dis[st]=0;
 51     queue<int>q;
 52     q.push(st);
 53     while(!q.empty()){
 54         int u=q.front();
 55         q.pop();
 56         vis[u]=false;
 57         for(int i=head[u];i;i=edge[i].next){
 58             node t=edge[i];
 59             if(t.flow&&dis[t.to]>dis[u]+t.cost+eps){
 60                 dis[t.to]=dis[u]+t.cost;
 61                 pre[t.to]=i;
 62                 if(!vis[t.to]){
 63                     vis[t.to]=true;
 64                     q.push(t.to);
 65                 }
 66             }
 67         }
 68     }
 69     if(dis[en]==INF)
 70         return false;
 71     return true;
 72 }
 73 
 74 void mcmf(int &flow,double &cost){
 75     while(spfa()){
 76         int mmin=INF;
 77         for(int i=pre[en];i;i=pre[edge[i^1].to]){
 78             mmin=min(mmin,edge[i].flow);
 79         }
 80         for(int i=pre[en];i;i=pre[edge[i^1].to]){
 81             edge[i].flow-=mmin;
 82             edge[i^1].flow+=mmin;
 83             cost+=edge[i].cost*mmin;
 84         }
 85         flow+=mmin;
 86     }
 87 }
 88 
 89 int main(){
 90     int T;
 91     scanf("%d",&T);
 92     while(T--){
 93         init();
 94         int n,m;
 95         scanf("%d%d",&n,&m);
 96         st=0,en=n+1;
 97         for(int i=1;i<=n;i++){
 98             int s,b;
 99             scanf("%d%d",&s,&b);
100             if(s-b>0) link(st,i,s-b,0);
101             if(s-b<0) link(i,en,b-s,0);
102         }
103         for(int i=1;i<=m;i++){
104             int u,v,flow;
105             double p;
106             scanf("%d%d%d%lf",&u,&v,&flow,&p);
107             p=-log(1-p);
108             if(flow>0) link(u,v,1,0);
109             if(flow>1) link(u,v,flow-1,p);
110         }
111         int flow=0;
112         double cost=0;
113         mcmf(flow,cost);
114         cost=exp(-cost);
115         printf("%.2f\n",1-cost);
116     }
117     return 0;
118 }

 

posted @ 2018-11-02 17:45  Yeader  阅读(163)  评论(0编辑  收藏  举报