顶点具有容量限制的网络流,建图时可以将点x拆成2个点,a,b,将从x进入的点改成从a进入,从x出去的点改成从b出,然后ab之间连一条INF容量的边,这样就可以直接利用网络流模板了。
利用上述建图方法,创建超级源点和超级汇点,二分答案,用最大流判断是否可行。
个人觉得这题最坑的地方就在于数据非常大,爆int,建议初始化时,二分上限<地图上限。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<string> #define eps 1e-12 #define INF 0x7fffffff #define fuck 0x7fffffffffffffLL #define maxn 3000 using namespace std; int n,m; int en; int st,ed; //源点和汇点 int dis[maxn] ;//dis[i],表示 到 原点 s 的 层数 int que[9999999]; struct edge { int to,c,next; }; edge e[9999999]; int head[maxn]; void add(int a,int b,int c) { e[en].to=b; e[en].c=c; e[en].next=head[a]; head[a]=en++; e[en].to=a; e[en].c=0; e[en].next=head[b]; head[b]=en++; } int bfs() { memset(dis,-1,sizeof(dis)); dis[st]=0; int front=0,rear=0; que[rear++]=st; while(front<rear) { int j=que[front++]; for(int k=head[j];k!=-1;k=e[k].next) { int i=e[k].to; if(dis[i]==-1&&e[k].c) { dis[i] = dis[j]+ 1 ; que[rear++]=i; if(i==ed) return true; } } } return false; } int dfs(int x,int mx) { int i,a; if(x==ed) return mx ; int ret=0; for(int k=head[x];k!=-1&&ret<mx;k=e[k].next) { if(e[k].c&&dis[e[k].to]==dis[x]+1) { int dd=dfs(e[k].to,min(e[k].c,mx)); e[k].c-=dd; e[k^1].c+=dd; mx-=dd; ret+=dd; } } if(!ret) dis[x]=-1; return ret; } int num[maxn],c[maxn]; int sum; long long mp[1005][1005]; void init() { en=0; st=0; ed=2*n+1; memset(head,-1,sizeof(head)); } void input() { int x,y; long long z; sum=0; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { mp[i][j]=fuck+1; } } for(int i=1;i<=n;i++) { scanf("%d%d",&x,&y); sum+=x; num[i]=x; c[i]=y; } for(int i=1;i<=m;i++) { scanf("%d%d%lld",&x,&y,&z); mp[x][y]=mp[y][x]=min(z,mp[x][y]); } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j||i==k||j==k) continue; mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]); } } } } void build(long long lim) { init(); for(int i=1;i<=n;i++) { /*顶点具有容量限制的网络流*/ add(st,i,num[i]); add(i,i+n,INF); add(i+n,ed,c[i]); for(int j=1;j<=n;j++) { if(mp[i][j]<=lim) { add(i,j+n,INF); } } } } int dinic() { int tmp=0; int maxflow=0; while(bfs()) { while(tmp=dfs(st,INF)) maxflow+=tmp; } return maxflow; } long long cal() { long long l=0,r=fuck; long long mid; long long ans=-1; while(l<=r) { mid=(l+r)>>1; build(mid); int tmp=dinic(); if(tmp==sum) {ans=mid;r=mid-1;} else l=mid+1; } return ans; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { input(); cout<<cal()<<endl; } }