链接: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);
}