luogu P3305 [SDOI2013]费用流

题目链接

bz似乎挂了...
luogu P3305 [SDOI2013]费用流

题解

dalao告诉我,这题
似乎很水....
懂了题目大意就可以随便切了
问1,最大流
问2,二分最大边权求,check是否为最大流
PS:今天代码很多bug....惨orz

代码

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
#define eps 1e-4
const int maxn = 5007;
using std::queue;
using std::min;
int n,m,S,T;

inline int read() {
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9') {if(f == '-') f = -1;c = getchar();}
    while(c <= '9'&&c >= '0') x = x * 10 + c - '0',c = getchar();
    return x*f;
}
struct node{
    int v;double flow;int next;
}edge[maxn<<2];
int head[maxn],num=1;
inline void add_edge(int u,int v,double flow) { edge[++num].v = v;edge[num].flow = flow;edge[num].next = head[u];head[u] = num; }
inline void ADD (int u,int v,double flow) {
    add_edge(u,v,flow);
    add_edge(v,u,0);
}
int a[maxn],b[maxn];double c[maxn];int lev[maxn],cur[maxn];
bool bfs() {
    for(int i = 0;i <= n;++ i) lev[i] = -1,cur[i] = head[i];
    queue<int>q;q.push(S),lev[S] = 0;
    while(!q.empty()) {
        int u = q.front();q.pop();
        for(int i = head[u];i;i = edge[i].next) {
            int v = edge[i].v;
            if(lev[v] == -1&&edge[i].flow > 0) 
                lev[v] = lev[u]+1,q.push(v);
        }
    }
    if(lev[T] != -1)return true;
    return false;
}
double dfs(int x,double flow) {
    if(x == T)return flow;
    double delta,rest = 0;
    for(int v,&i = cur[x];i;i = edge[i].next) {
        v = edge[i].v;
        if(lev[v] == lev[x]+1&&edge[i].flow > 0) {
            delta = dfs(v,std::min(flow - rest,edge[i].flow)); 
            if(delta) {
                edge[i].flow -= delta;
                edge[i^1].flow += delta;
                rest+=delta;if(rest == delta)break;
            }
        }
    }
    if(rest==flow) lev[x]=-1;
    return rest;
}

double Dinic() {
    double ret = 0;
    while(bfs()) 
    ret += dfs(S,INF); 
    return ret;
}
void rebuild(double mid) {
    memset(head,0,sizeof head);
    num=1;
    for(int i = 1;i <= m;++ i) {
        ADD(a[i],b[i],min(mid,c[i]));
    }
}
int main() {
    double p;
    n = read(),m = read(),scanf("%lf",&p);
    S=1;T=n;
    for (int i = 1;i <= m;++ i) scanf("%d%d%lf",&a[i],&b[i],&c[i]), ADD(a[i],b[i],c[i]);
    double Max_flow;
    Max_flow = Dinic();
    printf("%.0lf\n",Max_flow);
    double l = 0,r = 1000000086.0;
    while (r - l > eps) {
        double mid = (l + r) / 2;
        rebuild(mid);
        if(Dinic() != Max_flow) l = mid;
        else r = mid;
    }
    printf("%.4lf\n",l*p);
    return 0;
}

转载于:https://www.cnblogs.com/sssy/p/8660479.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值