POJ 2195 最小费用流

本文介绍了一种解决最小费用最大流问题的方法,并通过一个具体的编程实现案例进行了详细说明。作者首次尝试解决此类问题,总结了从寻找费用最小的路径到最终求得整个问题解答的过程。

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

题目链接

 第一次做最小费用流的问题,之前一直是盲点。

从这道题来看,我对最小费用最大流的理解是,在最大流约束的条件下,每次寻找可行路都找费用最小的那一条,做若干次最短路,直到最后没有增广路。

这道题点的总数可达到202,第一次交题的时候没注意,导致RE


#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define lson node<<1,l,l+r>>1
#define rson node<<1|1,(l+r>>1)+1,r
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int _maxNodes = 1e5+10;

struct Node{
    int x, y;
    Node(){}
    Node(int u, int v){
        x = u; y = v;
    }
};

Node man[210], house[210];
int n,m;
char graph[210][210];
int num_m, num_h;
int source, sink;
int cost[210][210], d[210][210];
int parent[210];
bool vis[210];
int mincost[210];
int ans;


void init(){
    for (int i = 0; i < n; i++){
        scanf("%s", graph[i]);
    }

    num_m = num_h = 0;
    for (int i = 0; i < n; i++){
        for (int j = 0; j < m; j++){
            if (graph[i][j] == 'H'){
                house[++num_h] = Node(i, j);
            }
            else if (graph[i][j] == 'm'){
                man[++num_m] = Node(i, j);
            }
        }
    }
    source =  0; sink = num_m + num_h + 1;

    memset(cost,0,sizeof cost);
    memset(d,0,sizeof d);
    for (int i = 1; i <= num_m; i++){
        d[source][i] = 1;
    }
    for (int i = 1; i <= num_m; i++){
        for (int j = 1; j <= num_h; j++){
            d[i][num_m+j] = 1;
            cost[i][num_m+j] = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
            cost[num_m+j][i] = -cost[i][num_m+j];
        }
    }
    for (int i = 1; i <= num_h; i++){
        d[num_m+i][sink] = 1;
    }
}


void SPFA(){
    queue<int> que;
    int v, i;
    memset(vis,false,sizeof(vis));
    memset(parent,-1,sizeof (parent));
    for (i = source; i <= sink; i++) mincost[i] = INF;

    que.push(source);
    mincost[source] = 0;
    vis[source] = true;

    while (!que.empty()){
        v = que.front(); que.pop();
        vis[v] = false;

        for (i = source; i <= sink; i++){
            if (d[v][i] && mincost[v] + cost[v][i] < mincost[i]){
                mincost[i] = mincost[v] + cost[v][i];
                parent[i] = v;
                if (!vis[i]){
                    que.push(i);
                    vis[i] = true;
                }
            }
        }
    }

}

void solve(){
    int v;
    ans = 0;
    while (1){
        SPFA();
        if (parent[sink] == -1) break;

        v = sink;
        while (parent[v] != -1){
            d[parent[v]][v] -= 1;
            d[v][parent[v]] += 1;
            v = parent[v];
        }
        ans += mincost[sink];
    }
    printf("%d\n",ans);
}

int main(){
    while (scanf("%d %d",&n, &m) == 2){
        if (n == 0 && m == 0) break;
        init();
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值