ZOJ 2404 Going Home 【最小费用最大流】

 思路:

把房子和人看成点,加上源点和汇点。

源点和每个人连容量为1,权值为0的边。

每个人和每个房子连容量为1,权值为距离的边。

每个房子和汇点连容量为1,权值为0的边。

#include<stdio.h>
#include<queue>
#define MAXN 500
#define MAXM 10002*4
#define INF  10000000
using namespace std;
//起点编号必须最小,终点编号必须最大
bool vis[MAXN];                    //spfa中记录是否在队列里边
char pho[105][105];
struct point{
    int x,y;
}man[105],house[105];
struct edge{
    edge *next,*op;                //op是指向反向边
    int t,c,v;                     //t下一个点编号,c容量,v权值
}ES[MAXM],*V[MAXN];                //ES边静态邻接表,V点的编号
int N,M,S,T,EC=-1;                 //S源点最小,T汇点最大,EC当前边数
int demond[MAXN],sp[MAXN],prev[MAXN]; //spSPFA中记录距离,prev记录上一个点路径
edge *path[MAXN];                  //与prev同步记录,记录到上一条边
void addedge(int a,int b,int v,int c=INF){
    //printf("%d %d %d %d
",a,b,v,c);
    edge e1={V[a],0,b,c,v},e2={V[b],0,a,0,-v};
    ES[++EC]=e1;V[a]=&ES[EC];
    ES[++EC]=e2;V[b]=&ES[EC];
    V[a]->op=V[b];V[b]->op=V[a];
}
int cal(point a,point b){
    return max(a.x-b.x,b.x-a.x)+max(a.y-b.y,b.y-a.y);
}
bool init(){
    int n,m;
    EC=-1;
    for(int i=0;i<=500;i++){
        V[i]=NULL;
    }
    scanf("%d%d",&n,&m);
    if(n==0&&m==0)return 0;
    for(int i=0;i<n;i++){
        scanf("%s",pho[i]);
    }
    int num_m=0,num_h=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(pho[i][j]=='m'){
                man[num_m++]={i,j};
            }
            else if(pho[i][j]=='H'){
                house[num_h++]={i,j};
            }
        }
    }
    for(int i=0;i<num_m;i++){
        for(int j=0;j<num_h;j++){
            addedge(i+1,num_m+j+1,cal(man[i],house[j]));
        }
    }
    for(int i=0;i<num_m;i++){
        addedge(0,i+1,0,1);
    }
    for(int i=0;i<num_h;i++){
        addedge(num_m+i+1,num_m+num_h+1,0,1);
    }
    S=0;T=num_m+num_h+1;
    return 1;
}
bool SPFA(){
    int u,v;
    for(u=S;u<=T;u++){
        sp[u]=INF;
    }
    queue<int>q;
    prev[S]=-1;
    q.push(S);
    sp[S]=0;
    vis[S]=1;
    while(!q.empty()){
        u=q.front();
        vis[u]=0;
        q.pop();
        for(edge *k=V[u];k;k=k->next){
            v=k->t;
            if(k->c>0&&sp[u]+k->v<sp[v]){
                sp[v]=sp[u]+k->v;
                prev[v]=u;
                path[v]=k;
                if(vis[v]==0){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return sp[T]!=INF;
}
int argument(){
    int i,cost=INF,flow=0;
    edge *e;
    for(i=T;prev[i]!=-1;i=prev[i]){
        e=path[i];
        if(e->c<cost)cost=e->c;
    }
    for(int i=T;prev[i]!=-1;i=prev[i]){
        e=path[i];
        e->c-=cost;e->op->c+=cost;
        flow+=e->v*cost;
    }
    return flow;
}
int maxcostflow(){
    int Flow=0;
    while(SPFA()){
        Flow+=argument();
    }
    return Flow;
}
int main(){
    while(init())
        printf("%d
",maxcostflow());
    return 0;
}
原文地址:https://www.cnblogs.com/tun117/p/5407631.html