二分答案+最大流。
對答案建圖,若長度≤答案,連邊即可。(先要預處理點對間的最短路)
當然得拆點,(否則,就此題而言,就會出現流量x-y不走x-y的最短路邊的情況,而是走了一條路徑 ,答案約束的僅僅是路徑上的邊長的最大值,而非總和)
流量:S – 某點入點 – 某點出點 – T
另外,由於此題卡實現,考慮二分邊權集合,就醬
吐槽 第一次建圖時“因為一頭牛經過邊(x,y,c)用時為c,所以對於時限t來說,這條邊的容量為t/c。 ”woc我在想什麼。。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=4e2+7;
const int L=2e6+7;
const int inf=0x3f3f3f3f3f3f3f3f;
int S=N-1,T=N-2;
int head[N],to[L],upp[L],last[L],cnt=1;
int que[N],lev[N],hd,tl;
inline void add_edge(int x,int y,int u1,int u2=0) {
to[++cnt]=y,upp[cnt]=u1,last[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,upp[cnt]=u2,last[cnt]=head[y],head[y]=cnt;
}
inline bool bfs() {
memset(lev,0,sizeof lev);
lev[S]=1;
que[hd=0,tl=1]=S;
while(hd<tl) {
int x=que[++hd];
for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && !lev[to[i]])
lev[to[i]]=lev[x]+1, que[++tl]=to[i];
}
return lev[T]!=0;
}
int dfs(int x,int tf) {
if(x==T) return tf;
int tot=0,tmp;
for(int i=head[x]; i; i=last[i]) if(upp[i]>0 && lev[x]+1==lev[to[i]]) {
tmp=dfs(to[i],min(tf-tot,upp[i]));
if(tmp) upp[i]-=tmp,upp[i^1]+=tmp,tot+=tmp;
if(tot==tf) break;
}
if(!tot) lev[x]=-1;
return tot;
}
int n,m,sum;
int s[210],p[210],dis[210][210];
struct edge {
int x,y,w;
bool operator<(const edge&d) const {
return w<d.w;
}
} c[40010];
int d[40010];
inline bool check(int lmt) {
cnt=1;
memset(head,0,sizeof head);
for(int i=1; i<=n; ++i) {
add_edge(S,i,s[i]);
add_edge(n+i,T,p[i]);
}
for(int i=1; c[i].w<=lmt && i<=m; ++i) {
add_edge(c[i].x,n+c[i].y,inf);
add_edge(c[i].y,n+c[i].x,inf);
}
int tot=0;
while(bfs()) tot+=dfs(S,inf);
return tot>=sum;
}
signed main() {
scanf("%lld%lld",&n,&m);
memset(dis,0x3f,sizeof dis);
for(int i=1; i<=n; ++i) {
scanf("%lld%lld",s+i,p+i);
dis[i][i]=0;
sum+=s[i];
}
for(int i=1,x,y,w; i<=m; ++i) {
scanf("%lld%lld%lld",&x,&y,&w);
if(dis[x][y]>w) {
dis[x][y]=w;
dis[y][x]=w;
}
}
for(int k=1; k<=n; ++k) {
for(int i=1; i<=n; ++i) {
for(int j=1; j<=n; ++j) {
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
m=0;
for(int i=1; i<=n; ++i) {
for(int j=i; j<=n; ++j) {
if(dis[i][j]<inf) c[++m]=(edge){i,j,dis[i][j]};
}
}
sort(c+1,c+m+1);
int l=1,r=0,mid,ans=-1;
for(int i=1; i<=m; ++i) {
if(c[i].w!=c[i-1].w) d[++r]=c[i].w;
}
while(l<=r) {
mid=(l+r)>>1;
if(check(d[mid])) ans=d[mid],r=mid-1;
else l=mid+1;
}
printf("%lld
",ans);
return 0;
}