[ABC397G] Maximize Distance

[ABC397G] Maximize Distance

题意

给出一个有向图,你需要选择 \(k\) 条边让它们的边权为 \(1\),剩余边的边权为 \(0\)。问 \(1\)\(n\) 的最短路长度的最大值为多少。

思路

最短路最大值显然二分答案,考虑给出最短路的长度如何计算最少需要的边数。

若最短路长度等于 \(1\),则问题就变为了选择最少的边使得从 \(1\)\(n\) 的每条路径都经过至少一条这些边。

设两点之间仅当边权为 \(0\) 时有边,则若 \(1\) 可以到达 \(n\),最短路长度为 \(0\),所以问题又变成了删去最少的边使得 \(1\) 不能到达 \(n\)

于是可以建图,边的流量为 \(1\),求最小割即可。

现在将该问题扩展到最短路长度不为 \(1\) 的情况。设最短路长度为 \(x\),于是我们建立 \(x\) 层图。若第 \(i\) 层有一条 \((x_i,y_i)\) 的边,则从第 \(i\) 层向第 \(i+1\) 层连 \((x_i,y_{i+1})\) 的边,流量为无限大。再将每层的 \(n\) 号点向第一层的 \(n\) 号点连边,流量同样为无限大,求最小割即可得到答案。

考虑为什么可以这么做。设跨层的边表示将路径长度加 \(1\)。若节点 \(1\) 可以到达第 \(i\) 层的 \(n\) 号节点,则经过了 \(i-1\) 条跨层的边,于是该层的最短路长度便为 \(i-1\),显然不满足条件。所以该图的一个割一定满足第 \(i\) 层的最短路长度为 \(i\),于是求出最小割便求出了答案。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=20005,INF=0x3f3f3f3f;
struct node{
	int x,w,rev,id;
};
vector<node> t[N];
int dep[N],gap[N],maxflow;
int n,m,k,S,T;
void add(int x,int y,int w){
	t[x].push_back({y,w,t[y].size()});
	t[y].push_back({x,0,t[x].size()-1});
}
void bfs(){
	memset(gap,0,sizeof(gap));
	memset(dep,-1,sizeof(dep));
	queue<int> q;
	q.push(T),dep[T]=0,gap[dep[T]]++;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(node v:t[u]){
			if(dep[v.x]==-1){
				dep[v.x]=dep[u]+1;
				gap[dep[v.x]]++,q.push(v.x);
			}
		}
	}
}
int dfs(int x,int flow){
	if(x==T){
		maxflow+=flow;
		return flow;
	}
	int used=0;
	for(int i=0;i<t[x].size();i++){
		int v=t[x][i].x;
		if(t[x][i].w&&dep[v]+1==dep[x]){
			int mn=dfs(v,min(t[x][i].w,flow-used));
			if(mn) t[x][i].w-=mn,t[v][t[x][i].rev].w+=mn,used+=mn;
			if(flow==used) return used;
		}
	}
	gap[dep[x]]--;
	if(!gap[dep[x]]) dep[S]=n*k+1;
	dep[x]++,gap[dep[x]]++;
	return used;
}
int isap(){
	maxflow=0;
	bfs();
	while(dep[S]<n*k) dfs(S,INF);
	return maxflow;
}
struct IN{
	int x,y;
}in[105];
bool check(int mid){
	for(int i=1;i<=n*k;i++)
		t[i].clear();
	for(int d=0;d<mid;d++){
		for(int i=1;i<=m;i++){
			add(d*n+in[i].x,d*n+in[i].y,1);
			if(d!=mid-1) add(d*n+in[i].x,(d+1)*n+in[i].y,INF);
		}
		if(d) add(d*n+n,n,INF);
	}
	return isap()<=k;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>m>>k;
	S=1,T=n;
	for(int i=1;i<=m;i++)
		cin>>in[i].x>>in[i].y;
	int l=1,r=k,mid,res=0;
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid))
			l=mid+1,res=mid;
		else
			r=mid-1;
	}
	cout<<res;
	return 0;
}
posted @ 2025-03-26 11:05  WuMin4  阅读(14)  评论(0)    收藏  举报