hdu 1533 going home (最小费用最大流)

本文探讨了如何运用最小费用最大流算法解决在给定条件下的房屋分配问题,其中涉及到构建流量图,利用SPFA算法进行最短路径搜索,并通过MCMF算法求解最小费用最大流。通过实例解析,清晰地展示了算法的应用过程。

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

hdu 1533 going home (最小费用最大流)

思路: 在一个n*m的矩形区域,有多个房子和多个人,问一个人选一个房子,一个人走到房子的花费为人和房子之间的曼哈顿距离,问所有人都走到房子里,总花费最小是多少?

题解:经典的MCMF,建图:虚拟一个源点source,和一个汇点sink,source指向所有人,每条边的权值为1,

每个房子都指向汇点,权值为1,对于一个人,和每个房子都有一条边,权值为1。

注意:还有一个花费数组,cost[][],记录人和房子间的距离,注意要和流量图一样建立反向边!原因如下图:


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
#define LL long long
#define M 205
#define N 102
#define DEBUG puts("It's here!")
#define INF 1<<29
#define CLS(x,v) memset(x,v,sizeof(x))
#define FOR(i,a,n)  for(int i=(a);i<=(n);++i)

int cap[M][M],cost[M][M];
int father[M],d[M];
bool vis[M];
int sourse,sink;
void spfa()
{
    queue<int> Q;
    CLS(vis,0);
    CLS(father,-1);
    for(int i=sourse;i<=sink;i++)d[i]=INF;
    d[sourse]=0;
    Q.push(sourse);
    int pre;
    while(!Q.empty())
    {
        pre=Q.front();
        Q.pop();
        vis[pre]=0;
        for(int i=sourse;i<=sink;i++)
        if(cap[pre][i]&&d[i]>d[pre]+cost[pre][i])
        {
            d[i]=d[pre]+cost[pre][i];
            father[i]=pre;
            if(!vis[i])
            {
                vis[i]=1;
                Q.push(i);
            }
        }
    }
}
void MCMF()
{
    int mincost=0;
    while(1)
    {
        spfa();
        if(father[sink]==-1)break;//汇点不可达
        for(int i=sink;i!=sourse;i=father[i])
        {
            cap[father[i]][i]-=1;
            cap[i][father[i]]+=1;
        }
        mincost+=d[sink];
    }
    printf("%d\n",mincost);
}
struct position
{
    int x,y;
} man[N],house[N];
int main()
{
    char s[N];
    int n,m;
    int a,b;
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        a=b=0;
        CLS(cap,0);
        CLS(cost,0);
        for(int i=0; i<n; i++)
        {
            scanf("%s",s);
            for(int j=0; j<m; j++)
            {
                if(s[j]=='m')
                    man[++a].x=i,man[a].y=j;
                if(s[j]=='H')
                    house[++b].x=i,house[b].y=j;
            }
        }
        //构图
        sourse=0;sink=a+b+1;
        for(int i=1; i<=a; i++)
        {
            cap[0][i]=1;
            for(int j=1; j<=b; j++)
            {
                cap[i][a+j]=1;
                cost[i][a+j]=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y);
                cost[a+j][i]=-cost[i][a+j];
            }
        }
        for(int i=a+1; i<sink; i++)
            cap[i][sink]=1;
        MCMF();
    }
    return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值