牛客练习赛43E.Tachibana Kanade And Dream City(网络流)

链接:https://ac.nowcoder.com/acm/contest/548/E
来源:牛客网

题目大意:

给你一个图,图上n个点每个点有两个权值vi,wi,还有m条边,每条边有一个cost,当你想将点u的vi权值经过这条边转移到v时,需要花费cost时间。现在你需要将所有的点的权值通过边进行处理,每个点最终都要满足一个条件:vi<=wi,问你需要时间最大的那个点的最小值是多少?

思路:

抛开要求时间的限制,我们直接考虑如何判断这些废水是否可以被处理。我们把每户人家看做一个点,发现限制主要是在点而不是在边,我们就可以很自然地将每个点 v 拆成两个点 v_1 和 v_2 ,建立源点 S和汇点 T,对于每一个 v,我们建立源点到 v_1 的弧,容量为该点一开始拥有废水的数量 v_i,v_2 连向 T 一条容量为废水处理数量 w_i 的弧。对于原图的每一条边 (a,b),连接 a_1 和 b_2 一条容量为无限大的弧。 该网络的最大流等价于最大能处理的废水数量

现在我们要求能处理前提下的最短时间,发现是让所有安排方案中花费时间最大的方案花费时间最小,我们发现「最大的时间花费最小」是一个经典的带有单调性的问题。首先跑 Floyd 确定任意两点间的最短路径,二分最大值 L 后直接对于每对最短距离 ≤L 的点对直接建立上述的边就可以了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=405,inf=1e9+1;
struct Edge
{
    int from,to,cap,flow;
};
struct Dinic
{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>G[maxn];
    bool vis[maxn];
    int d[maxn];
    int cur[maxn];
    void init(int n)
    {
        this->n=n;
        for(int i=0;i<n;i++)G[i].clear();
        edges.clear();
    }
    void Add(int from,int to,int cap)
    {
        edges.push_back((Edge){from,to,cap,0});
        edges.push_back((Edge){to,from,0,0});
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue<int>Q;
        Q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!Q.empty())
        {
            int x=Q.front();Q.pop();
            for(int i=0;i<G[x].size();i++)
            {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow)
                {
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x,int a)
    {
        if(x==t||a==0)return a;
        int flow=0,f;
        for(int& i=cur[x];i<G[x].size();i++)
        {
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
            {
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0)break;
            }
        }
        return flow;
    }
    int Maxflow(int s,int t)
    {
        this->s=s;this->t=t;
        int flow=0;
        while(bfs())
        {
            memset(cur,0,sizeof(cur));
            flow+=dfs(s,inf);
        }
        return flow;
    }
}solve;
int u[maxn],w[maxn],n,m;
ll d[maxn][maxn];
int ok(int mid)
{
    solve.init(n*2+2);
    int S=0,T=n*2+1,res=0;
    for(int i=1;i<=n;i++)
    {
        solve.Add(S,i,u[i]);
        solve.Add(i+n,T,w[i]);
        solve.Add(i,i+n,inf);
        res+=u[i];
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    if(d[i][j]&&d[i][j]<=mid)
    solve.Add(i,j+n,inf);
      
    return solve.Maxflow(S,T)==res;
}
void update(ll& x,ll y)
{
    x=min(x,y);
}
int main()
{
    int l=1,r=1e9,mid,a,b,c;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&u[i],&w[i]);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)d[i][j]=inf;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        update(d[a][b],c);
        update(d[b][a],c);
    }
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    update(d[i][j],d[i][k]+d[k][j]);
    while(l<r)
    {
        mid=(l+r)/2;
        if(ok(mid))r=mid;
        else l=mid+1;
    }
    if(!ok(l))puts("-1");
    else printf("%d\n",l);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值