poj2455二分构图网络流

题目描述

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.

算法思路

  1. 这个题目看起来很奇怪,求构造T条通路中最小的一条路的长度。
  2. 如果要正向求解,感觉很难来解,因为我们不知道如何来构造这些通路才可以达到这样的效果,只能采用暴力枚举状态压缩的方法来解决问题,这样做的时间复杂度是不可以想象的。
  3. 但是,通路的条数非常好算,在不允许重复的边存在的情况下,从S-T的通路的数量就是这个图的S-T最小割,进而可以转化成为网络流的问题。
  4. 所以,我们二分最长限制,如果求得的条数大于需要的数量,则搜下限,反之则搜上限。
  5. 还有就是在第一次存图的时候使用邻接表来减小空间,第二次构图的时候使用邻接矩阵,因为此时会存在重边,并不能有效的减小时间复杂度。

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值