【最小费用最大流】POJ 2195

本文深入探讨了费用流算法的实现细节,并通过一个具体的示例程序展示了如何使用该算法解决匹配问题。文章中详细解释了SPFA算法的应用以及如何进行代码调试,还特别提到了在实现过程中容易遇到的问题。

可以KM,也可以费用流,最近学费用流,所以用一下,debug真浪费时间,以为spfa有问题,原来是计数时出错。。。囧啊,菜啊,话说poj 2516到现在还不知道wa哪里,抓狂啊!!!

#define inf 1<<30
#define N 222
int cap[N][N];
int cost[N][N];
int pre[N];
int dis[N];
bool vis[N];
int minc;
char str[110][110];
int min(int a,int b){return a>b?b:a;}
void spfa(int s,int t){
    queue<int> qq;
    int i,j;
    while(1){
        for(i=s;i<=t;i++){
            vis[i] = 0;
            dis[i] = inf;
        }
        dis[s] = 0;
        qq.push(s);
        vis[s] = 1;
        while(!qq.empty()){
            int u = qq.front();
            qq.pop();
            vis[u] = 0;
            for(int v=s;v<=t;v++){
                if(cap[u][v] && dis[u] + cost[u][v] < dis[v]){
                    dis[v] = dis[u] + cost[u][v];
                    pre[v] = u;
                    if(!vis[v]){
                        vis[v] = 1;
                        qq.push(v);
                    }
                }
            }
        }
        if(dis[t] == inf){
            return ;
        }
        int a = inf;
        for(int u=t;u!=s;u=pre[u]){
            a = min(a,cap[pre[u]][u]);
        }
        for(int u=t;u!=s;u=pre[u]){
            cap[pre[u]][u] -= a;
            cap[u][pre[u]] += a;
        }
        minc += dis[t]*a;
    }
    return ;
}
struct node{
    int r,c;
}mm[N/2],hh[N/2];
int cntm ;
int cnth ;
void work(){
    int i,j;
    int s = 0,t = cntm + cnth + 1;
    minc =0;
    memset(cap,0,sizeof(cap));
    memset(cost,0,sizeof(cost));
    for(i=1;i<=cntm;i++){
        cap[s][i] = 1;//每条边容量为1,最后肯定是满流的
        cost[s][i] = 0;
    }
    for(i=1;i<=cnth;i++){
        cap[i+cntm][t] = 1;
        cost[i+cntm][t] = 0;
    }
    for(i=1;i<=cntm;i++){
        for(j=1;j<=cnth;j++){
            cap[i][j+cntm] = 1;
            cost[i][j+cntm] = abs(mm[i].r - hh[j].r) + abs(mm[i].c - hh[j].c);
            cost[j+cntm][i] = -cost[i][j+cntm];//注意要取反
        }
    }
    spfa(s,t);
    printf("%d\n",minc);
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m) && (n+m)){
        int i,j;
        for(i=1;i<=n;i++){
            scanf("%s",str[i]+1);
        }
        cntm = 0;
        cnth = 0;
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++){
                if(str[i][j] == 'm'){
                    mm[++cntm].r = i;
                    mm[cntm].c = j;
                } else if(str[i][j] == 'H'){
                    hh[++cnth].r = i;
                    hh[cnth].c = j;
                }
            }
        }cout<<cntm<<endl;
        work();
    }
    return 0;
}


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值