P2402 奶牛隐藏

漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P2402

 

题目背景

这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你。(奶牛混乱的原因看题目描述)

题目描述

在一个农场里有n块田地。某天下午,有一群牛在田地里吃草,他们分散在农场的诸多田地上,农场由m条无向的路连接,每条路有不同的长度。

突然,天降大雨,奶牛们非常混乱,想要快点去躲雨。已知每个田地都建立有一个牛棚,但是每个牛棚只能容纳一定数量的牛躲雨,如果超过这个数量,那多出的牛只能去别的田地躲雨。奶牛们每移动1的距离花费1时间,奶牛们想知道它们全部都躲进牛棚,最少需要多少时间。(即最后一头奶牛最少要花多久才能躲进牛棚)。

输入输出格式

输入格式:

第一行输入两个整数N,M。N表示田地块数,M表示路径数。

接下来N行,每行两个整数S,P,分别表示该田地现在有几头牛以及该田地的牛棚最多可以容纳多少牛。

接下来M行,每行3个整数A,B,C,表示存在一条路径连接A,B,并且它的长度为C。

输出格式:

一个整数表示所有奶牛全都躲进牛棚所用的最少时间。如果无法使全部奶牛都躲进牛棚,输出-1。

输入输出样例

输入样例#1: 复制
3 4 
7 2 
0 4 
2 6 
1 2 40 
3 2 70 
2 3 90 
1 3 120
输出样例#1: 复制
110

说明

【样例解释】

1号点的两只牛直接躲进1号牛棚,剩下的5只中,4只跑去2号点,还有一只从1->2->3,3号点的2只牛也直接躲进去,这样最慢的牛花费的时间是110。

数据范围 : 对于100%的数据,N<=200 M<=1500

// luogu-judger-enable-o2
//二分答案+floyd+网络流
//Floyd求出牧场间的最短路
//要拆点
//源点向每个牧场连边,容量为这个牧场上有几头牛
//牧场向汇点连边,容量为这个牧场的牛棚的容量
//然后,二分一个mid,两个牧场间距离<=mid加边,容量inf
//跑最大流
//如果最大流流量==牛的数量,调整上界
//否则调整下界
//最后选择满足的l和r输出

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int N=3e3+5;
const int M=3e5+5;
const long long INF=1LL<<50;

int n,m,S,T;
long long A[N],B[N];
long long dis[N][N];
int head[N],from[N],num_edge;
struct Edge
{
    int v,nxt;
    long long flow;
}edge[M];

inline long long read()
{
    char c=getchar();int num=0,f=1;
    for(;!isdigit(c);c=getchar())
        f=c=='-'?-1:f;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num*f;
}

inline void add_edge(int u,int v,long long flow)
{
    edge[++num_edge].v=v;
    edge[num_edge].flow=flow;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

int dep[N];
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    queue<int> que;
    que.push(S),dep[S]=1;
    int now,v;
    while(!que.empty())
    {
        now=que.front(),que.pop();
        for(int i=head[now];i;i=edge[i].nxt)
        {
            if(edge[i].flow)
            {
                v=edge[i].v;
                if(dep[v])
                    continue;
                dep[v]=dep[now]+1;
                if(v==T)
                    return 1;
                que.push(v);
            }
        }
    }
    return 0;
}

long long dfs(int now,long long flow)
{
    if(now==T)
        return flow;
    long long outflow=0,tmp;
    int v;
    for(int i=head[now];i;i=edge[i].nxt)
    {
        if(edge[i].flow)
        {
            v=edge[i].v;
            if(dep[v]!=dep[now]+1)
                continue;
            tmp=dfs(v,min(flow,edge[i].flow));
            if(tmp)
            {
                outflow+=tmp;
                flow-=tmp;
                edge[i].flow-=tmp;
                edge[i^1].flow+=tmp;
                if(!flow)
                    return outflow;
            }
        }
    }
    dep[now]=0;
    return outflow;
}

inline void build(long long mid)
{
    memset(head,0,sizeof(head));
    num_edge=1;
    for(int i=1;i<=n;++i)
    {
        add_edge(S,i,A[i]);
        add_edge(i,S,0);
    }
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            if(dis[i][j]<=mid)
                add_edge(i,j+n,INF),add_edge(j+n,i,0);
    for(int i=1;i<=n;++i)
        add_edge(i+n,T,B[i]),
        add_edge(T,i+n,0);
}

long long Flow;
inline bool dinic()
{
    long long flow=0;
    while(bfs())
        flow+=dfs(S,INF);
    return flow==Flow;
}

int main()
{
    num_edge=1;
    n=read(),m=read();
    T=n*2+1;
    for(int i=1,a;i<=n;++i)
    {
        A[i]=read(),B[i]=read();
        Flow+=A[i];
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;++j)
            dis[i][j]=INF;
        dis[i][i]=0;
    }
    long long c;
    for(int i=1,a,b;i<=m;++i)
    {
        a=read(),b=read(),c=read();
        dis[a][b]=min(dis[a][b],c);
        dis[b][a]=dis[a][b];
    }
    for(int k=1;k<=n;++k)
        for(int i=1;i<=n;++i)
        {
            if(k==i)
                continue;
            for(int j=1;j<=n;++j)
            {
                if(i==j||j==k)
                    continue;
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    long long L=INF,R=-INF,mid;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
        {
            if(dis[i][j]==INF)
                continue;
            L=min(L,dis[i][j]);
            R=max(R,dis[i][j]);
        }
    bool flag=0;
    while(L+1<R)
    {
        mid=L+R>>1;
        build(mid);
        if(dinic())
            R=mid;
        else
            L=mid;
    }
    build(L);
    if(dinic())
        printf("%lld",L);
    else
    {
        build(R);
        if(dinic())
            printf("%lld",R);
        else
            printf("-1");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/lovewhy/p/8665929.html