那似乎必须要二分答案了,要不然最大流没这个功能啊!!
我们检测 时间内能否满足条件
源点连向每个田,流量为一开始田的奶牛
每个田连向汇点,流量为能容纳的奶牛,流向汇点代表住在这个牛棚
两地的距离如果小于 ,连边,边权
跑最大流检验满流即可
但是有问题,比如1能到2,2能到3,推出1也能到3,但实际上1到不了3
其余都一样了
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
#define int long long
const int inf=1e18;
int n,m,s,t,ss[maxn],p[maxn],dis[maxn],l[maxn],r[maxn],w[maxn],ju[209][209];
struct edge{
int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs()
{
for(int i=s;i<=t;i++) dis[i]=0;
dis[s]=1;
queue<int>q; q.push( s );
while( !q.empty() )
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( d[i].flow&&dis[v]==0 )
{
dis[v]=dis[u]+1;
if( v==t ) return true;
q.push( v );
}
}
}
return false;
}
int dinic(int u,int flow)
{
if( u==t ) return flow;
int res=flow;
for(int i=head[u];i&&res;i=d[i].nxt )
{
int v=d[i].to;
if( dis[v]==dis[u]+1&&d[i].flow)
{
int temp=dinic(v,min(res,d[i].flow) );
if( temp==0 ) dis[v]=0;
res-=temp;
d[i].flow-=temp;
d[i^1].flow+=temp;
}
}
return flow-res;
}
bool isok( int mid )
{
s=0,t=n*2+1;
int sumn=0;
cnt=1;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if( ju[i][j]<=mid ) add(i,j+n,inf);
}
for(int i=1;i<=n;i++)
{
add(s,i,ss[i]);
add(i+n,t,p[i]); sumn+=ss[i];
add(i,i+n,inf);
}
int ans=0;
while( bfs() ) ans+=dinic(s,inf);
if( ans!=sumn ) return false;
return true;
}
signed main()
{
cin >> n >> m;
for(int i=1;i<=n;i++) cin >> ss[i] >> p[i];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if( i==j ) ju[i][j]=0;
else ju[i][j]=inf;
for(int i=1;i<=m;i++)
{
cin >> l[i] >> r[i] >> w[i];
ju[l[i]][r[i]]=ju[r[i]][l[i]]=min( w[i],ju[l[i]][r[i]] );
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ju[i][j]=min( ju[i][j],ju[i][k]+ju[k][j] );
int ll=0,rr=inf-1,mid,ans=-1;
while( rr>=ll )
{
mid=ll+rr>>1;
if( isok(mid) ) rr=mid-1,ans=mid;
else ll=mid+1;
}
cout << ans;
}