BZOJ 4501 旅行


题目大意 : http://www.lydsy.com/JudgeOnline/problem.php?id=4501


首先对于每一个节点,如果f[u] max , 那么每一个 v 都应取到相应的max,那么我们可以按拓扑序逆序(也就是dfs序的逆序) 先算出来每一个f[v],然后再考虑每一个节点的更新,按题意来说, f[u]=f[v]+1 的最大值,由于是分式,我们考虑用01分数规划搞,我们设当前二分出来的值为mid , 则应满足 f[v] + 1 - 边数×mid >0 ,由于有限制条件,即有y边必须有x,就是一个典型的最小割了

#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-7;
const int MAXN = 50005,MAXM = 500005,S = 0,T = 5001,inf = 0x7fffffff;
bool vis[MAXN];
int n,m,k; double f[MAXN];
vector<int>G[MAXN];


template<typename _t>
inline _t read(){
    _t x=0,f=1;
    char ch=getchar();
    for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48);
    return x*f;
}

struct Max_flow{
    int first[MAXN],e,d[MAXN],Q[MAXN];
    Max_flow(){clear();}
    struct edge{
        int u,v,next,id;double w;
    }a[MAXM];

    inline void clear(){
        memset(first,0,sizeof first); e = 2;
    }
    inline void add(int u,int v,int w){
        a[e].u = u;a[e].v = v;a[e].id = w;
        a[e].next = first[u];first[u] = e++;
    }
    inline void add(int u,int v,double w){
        a[e].u = u;a[e].v = v;a[e].w = w;
        a[e].next = first[u];first[u] = e++;
    }

    inline void push(int u,int v,double w){
        add(u,v,w);add(v,u,0.0);
    }

    inline bool bfs(){
        memset(d,-1,sizeof d); d[S] = 0;
        int l = 0,r = 1;Q[l] = S;
        while(l<r) {
            int u = Q[l++];
            for(int i = first[u];i;i=a[i].next) 
                if(d[a[i].v] == -1 && a[i].w) d[a[i].v] = d[u] + 1,Q[r++] = a[i].v;
        }
        return d[T] != -1;
    }

    inline double dfs(int u,double cap) {
        if(u == T || cap == 0) return cap;
        double Ans = 0.0;
        for(int i = first[u];i;i=a[i].next) {
            register int v = a[i].v; double w = a[i].w;
            if(d[v] == d[u] + 1 && w) {
                w = dfs(v,min(w,cap - Ans));
                Ans += w;
                a[i].w -= w;
                a[i^1].w += w;
                if(Ans == cap) return Ans;
            }
        }
        if(Ans == 0) d[u] = -1;
        return Ans;
    }

    inline double dinic(){
        double Ans = 0.0;
        while(bfs()) Ans += dfs(S,inf);
        return Ans;
    }

    inline void build_limit(int u){
        int sz = G[u].size();
        for(int i = 0;i<sz;i++) push(u,G[u][i],inf); 
    }

    inline void __dfs__(int);
}QAQ,QWQ;

inline void Max_flow::__dfs__(int u){
    if(vis[u]) return; vis[u] = 1;
    double l = 0.0,r = 0.0,Ans,mid;
    for(int i = first[u];i;i=a[i].next) {
        __dfs__(a[i].v);
        r = max(r,f[a[i].v] + 1.0);
    }
    while(l+1e-7<r) {
        Ans = 0.0; mid = (l + r)/2.0; QWQ.clear();
        for(int i = first[u];i;i=a[i].next) {
            register int v = a[i].v; QWQ.build_limit(a[i].id);
            if(f[v] + 1 < mid)  QWQ.push(S,a[i].id,mid - f[v] - 1);
            else QWQ.push(a[i].id,T,f[v] + 1 - mid),Ans += f[v] + 1 - mid;
        }
        if(Ans > QWQ.dinic()) f[u] = mid , l = mid;
        else r = mid;
    }
    // f[u] = max(f[v] + 1 / num > L)
    // --> f[v] + 1 - num * L > 0;
    // --> sigema(f[v] + 1 - num) > 0;
}

int main(){
    n = read<int>();m = read<int>(); k = read<int>();
    for(int i = 1;i<=m;i++) {
        register int u = read<int>(),v = read<int>();
        QAQ.add(u,v,i); 
    }
    for(int i = 1;i<=k;i++) {
        register int u = read<int>(),v = read<int>();
        G[v].push_back(u);
    }
    QAQ.__dfs__(1);
    printf("%lf\n",f[1]);
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值