BZOJ3597 [Scoi2014]方伯伯运椰子

Description

 

Input

 第一行包含二个整数N,M

接下来M行代表M条边,表示这个交通网络
每行六个整数,表示Ui,Vi,Ai,Bi,Ci,Di
接下来一行包含一条边,表示连接起点的边

Output

一个浮点数,保留二位小数。表示答案,数据保证答案大于0

Sample Input

5 10
1 5 13 13 0 412
2 5 30 18 396 148
1 5 33 31 0 39
4 5 22 4 0 786
4 5 13 32 0 561
4 5 3 48 0 460
2 5 32 47 604 258
5 7 44 37 75 164
5 7 34 50 925 441
6 2 26 38 1000 22

Sample Output

103.00

HINT

 1<=N<=5000

0<=M<=3000
1<=Ui,Vi<=N+2
0<=Ai,Bi<=500
0<=Ci<=10000
0<=Di<=1000

题解:

       假定点权为一个点的入流-出流,显然调整前后所有点权为0.

       将一条边容量-1,等价于使起点点权+1,终点点权-1,并付出a-d的代价;将一条边容量+1,等价于使终点点权+1,起点点权-1,并付出b+d的代价。我们将每条边拆为两条边,分别表示扩容和压缩,每条边权值为代价,起点为点权+1的点。

       由于最后所有点权是0,可知最后产生代价的边形成一个环。

       如果这张图中有负环,沿着负环调整会使费用减小。设减小的费用是val,环上边数位k,考虑先二分一个答案mid,则需验证是否有val/k>=mid。将所有的边权加上mid,原问题等价于判是否有负环。

#include<bits/stdc++.h>
using namespace std;
const int N=505;
const int M=1e4+10;
 
int n,m,E;
int fir[N],nex[M],arr[M],vis[N];
double len[M],dis[N];
 
void Add_Edge(int x,int y,double l) {
    nex[++E]=fir[x]; fir[x]=E;
    arr[E]=y; len[E]=l;
}
 
int Spfa(int x) {
    for (int i=fir[x];i;i=nex[i])
        if (dis[arr[i]]>dis[x]+len[i]) {
            if (vis[arr[i]]) return 0;
            vis[arr[i]]=1;
            dis[arr[i]]=dis[x]+len[i];
            if (!Spfa(arr[i])) return 0;
        }
    vis[x]=0;
    return 1;
}
 
int check(double mid) {
    for (int i=1;i<=E;i++) len[i]+=mid;
    for (int i=1;i<=n+2;i++) dis[i]=0x3f3f3f3f; dis[n+1]=0;
    memset(vis,0,sizeof(vis)); vis[n+1]=1;
    int t=!Spfa(n+1);
    for (int i=1;i<=E;i++) len[i]-=mid;
    return t;
}
 
int main() {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m+1;i++) {
        int x,y,a,b,c,d; scanf("%d%d%d%d%d%d",&x,&y,&a,&b,&c,&d);
        Add_Edge(x,y,b+d);
        if (c) Add_Edge(y,x,a-d);
    }
    double l=0,r=0x3f3f3f3f;
    while (r-l>=1e-4) {
        double mid=(l+r)/2;
        if (check(mid)) l=mid;
        else r=mid;
    }
    printf("%.2f",l);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值