题目描述
Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within his farm and needs to be able to get to the machine without being detected. He must make a total of T (1 <= T <= 200) trips to the machine during its construction. He has a secret tunnel that he uses only for the return trips.
The farm comprises N (2 <= N <= 200) landmarks (numbered 1..N) connected by P (1 <= P <= 40,000) bidirectional trails (numbered 1..P) and with a positive length that does not exceed 1,000,000. Multiple trails might join a pair of landmarks.
To minimize his chances of detection, FJ knows he cannot use any trail on the farm more than once and that he should try to use the shortest trails.
Help FJ get from the barn (landmark 1) to the secret milking machine (landmark N) a total of T times. Find the minimum possible length of the longest single trail that he will have to use, subject to the constraint that he use no trail more than once. (Note well: The goal is to minimize the length of the longest trail, not the sum of the trail lengths.)
It is guaranteed that FJ can make all T trips without reusing a trail.
算法思路
- 这个题目看起来很奇怪,求构造T条通路中最小的一条路的长度。
- 如果要正向求解,感觉很难来解,因为我们不知道如何来构造这些通路才可以达到这样的效果,只能采用暴力枚举状态压缩的方法来解决问题,这样做的时间复杂度是不可以想象的。
- 但是,通路的条数非常好算,在不允许重复的边存在的情况下,从S-T的通路的数量就是这个图的S-T最小割,进而可以转化成为网络流的问题。
- 所以,我们二分最长限制,如果求得的条数大于需要的数量,则搜下限,反之则搜上限。
- 还有就是在第一次存图的时候使用邻接表来减小空间,第二次构图的时候使用邻接矩阵,因为此时会存在重边,并不能有效的减小时间复杂度。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 205
#define MAXM 40005
#define INF 0x3f3f3f3f
struct Edge{
int from,to;
int len;
int next;
}tunnel[MAXM];
int n,m,e,k;
int head[MAXN],height[MAXN];
int grid[MAXN][MAXN];
void get_Graph(int limit)
{
int i;
memset(grid,0,sizeof(grid));
for(i=0;i<m;i++){
if(tunnel[i].len<=limit){
grid[tunnel[i].from][tunnel[i].to]++;
grid[tunnel[i].to][tunnel[i].from]++;
}
}
return;
}
bool Bfs(int src,int des)
{
queue<int>Q;
memset(height,-1,sizeof(height));
height[src]=0;
Q.push(src);
int i;
while(!Q.empty()){
int cur = Q.front();
Q.pop();
for(i=1;i<=n;i++){
if(height[i]<0&&grid[cur][i]>0){
height[i]=height[cur]+1;
Q.push(i);
}
}
}
return height[des]>=0;
}
int Dfs(int cur,int contain)
{
if(cur == n)return contain;
int i;
int use=0;
for(i=1;i<=n;i++){
if(grid[cur][i]>0&&height[i]==height[cur]+1){
int used = Dfs(i,min(contain,grid[cur][i]));
use += used;
contain -= used;
grid[cur][i] -= used;
grid[i][cur] += used;
}
if(contain<=0)break;
}
//if there is no network flow in the node
//then mark it to prevent unnecessary search
if(!use)height[cur]=-2;
return use;
}
int Dinic(int src,int des)
{
int ans=0;
while(Bfs(src,des)){
ans += Dfs(src,INF);
}
return ans;
}
int main()
{
freopen("input","r",stdin);
int i,ans;
int minlen = INF;
int maxlen = -1;
scanf("%d%d%d",&n,&m,&k);
for(i=0;i<m;i++){
scanf("%d%d%d",&tunnel[i].from,&tunnel[i].to,&tunnel[i].len);
minlen = min(tunnel[i].len,minlen);
maxlen = max(tunnel[i].len,maxlen);
}
while(minlen<=maxlen){
int mid = minlen+(maxlen-minlen)/2;
get_Graph(mid);
if(Dinic(1,n)>=k)
maxlen = mid-1;
else minlen=mid+1;
}
printf("%d\n",minlen);
return 0;
}