hrbust 1798 秘密产奶机器 (最大流+二分答案)

本文探讨了如何通过最大流算法解决特定路径选择问题,包括构建加权图、二分最长路径长度并验证路径数量及长度限制。适用于理解算法在路径规划与优化中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:他必须要走T(1<=T<=200)次通向他的机器的路径。走向目标点这T次走的路径中,他需要经过的所有道路里最长的道路最短可以是多少。

学校解题报告: 不同的路径总数的求法: 我们可以为原图中存在的边<u,v>建立一条从u到v 容量为1的边,由于是无向图,还要建一条从v到u容量为1的边, 以起点为源点,终点为汇点,求出最大流即为不同的路径数。这题不仅要求不同的路径数>=T, 还要求在这个前提下,所有道路中最长的道路最短。那么我们可以二分所有道路中的最长道路的长度L,重新建图,只在满足道路长度<=L的道路可以建双向的容量为1的边。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define INF 0x1f1f1f
typedef  struct {
    int v, next, val;
} edge;
const int MAXN = 20010;
const int MAXM = 500010;
edge e[MAXM];
int p[MAXN], eid;
inline void init() {
    memset(p, -1, sizeof(p));
    eid = 0;
}
//有向
inline void insert1(int from, int to, int val) {
    e[eid].v = to;
    e[eid].val = val;
    e[eid].next = p[from];
    p[from] = eid++;
    swap(from, to);
    e[eid].v = to;
    e[eid].val = 0;
    e[eid].next = p[from];
    p[from] = eid++;
}
//无向
inline void insert2(int from, int to, int val) {
    e[eid].v = to;
    e[eid].val = val;
    e[eid].next = p[from];
    p[from] = eid++;
    swap(from, to);
    e[eid].v = to;
    e[eid].val = val;
    e[eid].next = p[from];
    p[from] = eid++;
}
int n, m; //n为点数 m为边数
int h[MAXN];
int gap[MAXN];
int source, sink;
inline int dfs(int pos, int cost) {
    if (pos == sink) {
        return cost;
    }
    int j, minh = n - 1, lv = cost, d;
    for (j = p[pos]; j != -1; j = e[j].next){
        int v = e[j].v, val = e[j].val;
        if(val > 0){
            if (h[v] + 1 == h[pos]) {
                if (lv < e[j].val) d = lv;
                else d = e[j].val;
                d = dfs(v, d);
                e[j].val -= d;
                e[j ^ 1].val += d;
                lv -= d;
                if (h[source] >= n)return cost - lv;
                if (lv == 0)break;
            }
            if (h[v] < minh)minh = h[v];
        }
    }
    if (lv == cost) {
        --gap[h[pos]];
        if (gap[h[pos]] == 0)h[source] = n;
        h[pos] = minh + 1;
        ++gap[h[pos]];
    }
    return cost - lv;
}
int sap(int st, int ed) {

    source = st;
    sink = ed;
    int ret = 0;
    memset(gap, 0, sizeof(gap));
    memset(h, 0, sizeof(h));
    gap[0] = n;
    while (h[st] < n)ret += dfs(st, INF);
    return ret;
}
struct node{
    int x,y,w;
}road[40010];
int ok(int len,int T){
    int i;
    init();
    for(i=0;i<m;i++){
        if(road[i].w<=len)
        insert2(road[i].x,road[i].y,1);
    }
    if(sap(1,n)>=T)return 1;
    else return 0;
}
int main()
{
    int T,a,b,maxlen,i;
    while(scanf("%d%d%d",&n,&m,&T)!=EOF){
        maxlen=-1;
        for(i=0;i<m;i++){
            scanf("%d%d%d",&road[i].x,&road[i].y,&road[i].w);
            if(road[i].w>maxlen)maxlen=road[i].w;
        }
        int mid,l=0,r=maxlen,res;
        while(l<=r){
            mid=(l+r)/2;
            if(ok(mid,T)){
                r=mid-1;
                res=mid;
            }
            else l=mid+1;
        }
        printf("%d\n",res);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值