BZOJ3130 [Sdoi2013]费用流

16 篇文章 0 订阅
7 篇文章 0 订阅

瞎YY一下发现显然在方案确定的情况下把所有费用分配在流量最大的边上最优,于是只要二分最大流量每次容量和二分的值取min跑最大流看是否和原最大流相等即可。

流量可以是小数!!坑死我了,我还以为保留小数是逗你玩呢

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<vector>
#include<set>
using namespace std;
#define MAXN 110
#define MAXM 2010
#define INF 1000000000
#define MOD 1000000007
#define ll long long
#define eps 1e-8
struct vec{
    int to;
    int fro;
    double v;
};
vec mp[MAXM];
int tai[MAXN],cnt=1;
int d[MAXN];
int q[MAXN],hd,tl;
int s,t;
int v1[MAXM],v2[MAXM],v[MAXM];
int n,m,p;
double mf;
inline void be(int x,int y,double z){
    mp[++cnt].to=y;
    mp[cnt].fro=tai[x];
    tai[x]=cnt;
    mp[cnt].v=z;
}
inline void bse(int x,int y,double z){
    be(x,y,z);
    be(y,x,0);
}
bool bfs(){
    int i,x,y;
    memset(d,0,sizeof(d));
    d[1]=1;
    hd=tl=0;
    q[tl++]=1;
    while(hd!=tl){
        x=q[hd++];
        for(i=tai[x];i;i=mp[i].fro){
            y=mp[i].to;
            if(!d[y]&&mp[i].v>0){
                d[y]=d[x]+1;
                q[tl++]=y;
            }
        }
    }
    return d[t];
}
double dfs(int x,double mx){
    if(x==t){
        return mx;
    }
    int i,y;
    double tmp,re=0;
    for(i=tai[x];i;i=mp[i].fro){
        y=mp[i].to;
        if(d[y]==d[x]+1&&mp[i].v>0){
            tmp=dfs(y,min(mx,mp[i].v));
            re+=tmp;
            mx-=tmp;
            mp[i].v-=tmp;
            mp[i^1].v+=tmp;
            if(mx<eps){
                return re;
            }
        }
    }
    if(re<eps){
        d[x]=0;
    }
    return re;
}
bool OK(double x){
    int i;
    cnt=1;
    memset(tai,0,sizeof(tai));
    for(i=1;i<=m;i++){
        bse(v1[i],v2[i],min(x,1.0*v[i]));
    }
    double re=0;
    while(bfs()){
        re+=dfs(s,INF);
    }
    return fabs(re-mf)<eps;
}
int main(){
    int i;
    scanf("%d%d%d",&n,&m,&p);
    s=1;
    t=n;
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&v1[i],&v2[i],&v[i]);
        bse(v1[i],v2[i],v[i]);
    }
    while(bfs()){
    //  cout<<dfs(s,INF)<<'#'<<endl;
        mf+=dfs(s,INF);
    }
    double l=0,r=50000;
    double ans;
    while(fabs(l-r)>eps){
        double mid=(l+r)/2;
        if(OK(mid)){
            ans=mid;
            r=mid;
        }else{
            l=mid;
        }
    }
    printf("%d\n%.4lf\n",int(mf),1.0*p*ans);
    return 0;
}
 
/*
6 6 1
1 2 2
2 3 2
3 6 2
1 4 2
4 5 4
5 6 2
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值