最小费用最大流;HDU1533

本文介绍了一个简单的费用流算法实现案例,通过建立伴随网络并利用SPFA算法寻找最短路径进行增广来解决分配问题。文章详细展示了算法的具体实现步骤及核心代码。

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

//第一次写费用流,有些地方还是不太懂,但是思路很简单。
//建立伴随网络后,每次用spfa找最短路然后增广就好了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#define maxN 300
#define maxM 10005
#define INF 0xffffff
using namespace std;

struct node
{
    int c;//容量
    int f;//流量
    int c_f;//残留容量
    int val;//价值
}G[maxN][maxN];
int n,m;
int pre[maxM];//记录前驱点
int dist[maxM];//spfa记录距离
char coord[maxN][maxN];//坐标集
int inq[maxM];
int min_f;
int sum;
int vertex;

struct House
{
    int x;
    int y;
}house[maxN];

struct Man
{
    int x;
    int y;
}man[maxN];

void init()
{
    sum=0;
    int mcase,hcase;
    mcase=hcase=0;
    int i,j;
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            cin>>coord[i][j];
            if(coord[i][j]=='m'){
                mcase++;
                man[mcase].x=i;
                man[mcase].y=j;
            }
            if(coord[i][j]=='H'){
                hcase++;
                house[hcase].x=i;
                house[hcase].y=j;
            }
        }
    }
    vertex=hcase+mcase+1;
    for(int u=0;u<=vertex;u++)
    {
        for(int v=0;v<=vertex;v++)
        {
            G[u][v].c=G[v][u].c=0;
            G[u][v].f=G[v][u].f=0;
            G[u][v].c_f=G[v][u].c_f=0;
            G[u][v].val=G[v][u].val=INF;
        }
    }
    for(i=1;i<=mcase;i++)
    {
        G[0][i].val=0;
        G[0][i].c_f=G[0][i].c=1;
        for(j=1;j<=hcase;j++)
        {
            int len=abs((house[j].x-man[i].x))+abs(house[j].y-man[i].y);
            G[i][mcase+j].val=len;
            G[i][mcase+j].c=1;
            G[i][mcase+j].c_f=1;
            G[mcase+j][vertex].c=1;
            G[mcase+j][vertex].c_f=1;
            G[mcase+j][vertex].val=0;
        }
    }
}

void spfa(int s)
{
    queue<int> q;
    int i;
    for(i=0;i<maxN;i++)
    {
        dist[i]=INF;
        pre[i]=-1;
        inq[i]=0;
    }
    dist[s]=0;
    inq[i]=1;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(i=0;i<=vertex;i++)
        {
            if(G[u][i].c_f==0) continue;
            if(G[u][i].val==INF) G[u][i].val=-G[i][u].val;
            //不太懂
            if(dist[i]>dist[u]+G[u][i].val)
            {
                dist[i]=dist[u]+G[u][i].val;
                pre[i]=u;
                if(!inq[i])
                {
                    q.push(i);
                    inq[i]=1;
                }
            }
        }
    }
}

void argument(int s,int t)
{
    spfa(s);
    int v;
    while(pre[t]!=-1)
    {
        int u=pre[t];
        v=t;
        sum+=dist[v];
        min_f=INF;
        while(u!=-1)
        {
            if(G[u][v].c_f<min_f)
                min_f=G[u][v].c_f;
            v=u;
            u=pre[v];
        }
        u=pre[t];v=t;
        while(u!=-1)
        {
            G[u][v].f+=min_f;
            G[v][u].f=-G[u][v].f;
            G[u][v].c_f=G[u][v].c-G[u][v].f;
            G[v][u].c_f=G[v][u].c-G[v][u].f;
            v=u;
            u=pre[v];
        }
        spfa(s);
    }
}

int main()
{
    while(cin>>n>>m)
    {
        if(n==0&&m==0) break;
        init();
        argument(0,vertex);
        cout<<sum<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值