POJ - 2135 Farm Tour

本文介绍了一种解决从起点到终点再返回起点的问题的方法——最小费用最大流(MCMF)算法,并提供了一个具体的C++实现示例。该算法应用于寻找路径最短且每条边仅能经过一次的情况。

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

就是从1走到n然后再走回来,一条边只能走一次,要求路径最短。

// MCMF 最小费用最大流
#include <cstdio>
#include <vector>
#include <string>
#include <string.h>
#include <queue>

#define MAX 1000 + 5
#define INF 0x3fffffff

using namespace std;

struct Edge {
    int from, to, cap, flow, cost;
    Edge( int u, int v, int ca, int f, int co ) : from(u),to(v),cap(ca),flow(f),cost(co){};
};

int n,m,s,t;
vector<Edge> edges;
vector<int> G[MAX];
int inq[MAX];//是否在队列中
int d[MAX];//距离
int p[MAX];//上一条弧
int a[MAX];//可改进量

void init( int n ) {//初始化
    for( int i = 0; i < n; i++ )
        G[i].clear();
    edges.clear();
}

void addEdge( int from, int to, int cap, int cost ) { //加边
    edges.push_back( Edge( from, to, cap, 0, cost ) );
    edges.push_back( Edge( to, from, 0, 0, -cost ) );
    int m = edges.size();
    G[from].push_back( m - 2 );
    G[to].push_back( m - 1 );
}

bool SPFA( int s, int t, int &flow, int &cost ) { //寻找最小费用的增广路,使用引用同时修改原flow,cost
    fill( d, d + MAX, INF );
    memset( inq, 0, sizeof( inq ) );

    // 源点入队部分
    d[s] = 0;
    inq[s] = 1;
    p[s] = 0;
    a[s] = INF;

    queue<int> q;
    q.push( s );
    while( !q.empty () ) {
        int u = q.front();
        q.pop();
        inq[u]--;
        for( int i = 0; i < G[u].size(); i++ ) {
            Edge& e = edges[G[u][i]];
            if( e.cap > e.flow && d[e.to] > d[u] + e.cost ) { //满足可增广且可变短
                d[e.to] = d[u] + e.cost;
                p[e.to] = G[u][i];
                a[e.to] = min( a[u], e.cap - e.flow );
                if( !inq[e.to] ) {
                    inq[e.to]++;
                    q.push(e.to);
                }
            }
        }
    }
    if( d[t] == INF ) return false; //汇点不可达则退出
    flow += a[t];
    cost += d[t] * a[t];
    int u = t;
    while( u != s ) { //更新正向边和反向边
        edges[p[u]].flow += a[t];
        edges[p[u] ^ 1].flow -= a[t];
        u = edges[p[u]].from;
    }
    return true;
}

int MincotMaxflow( int s, int t, int cnt ) {
    int flow = 0, cost = 0;
    //while( SPFA( s, t, flow, cost ) );
    while( cnt > 0 ) {
        SPFA( s, t, flow, cost );
        cnt--;
    }
    return cost;
}

int main() {
    int a, b, c;
    while( ~scanf( "%d%d", &n, &m ) ) {
        init( n );
        for( int i = 0; i < m; i++ ) {
            scanf( "%d%d%d", &a, &b, &c );
            addEdge( a - 1, b - 1, 1, c );
            addEdge( b - 1, a - 1, 1, c );
        }
        printf( "%d\n", MincotMaxflow( 0, n - 1, 2 ) );
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值