• 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;
    }
  • 相关阅读:
    HTTP代理简介
    解决键盘Alt+Win键功能反了的问题
    设置锁屏后关闭显示器时间
    通过ffmpeg下载在线HTTP Live Stream视频
    一款好用的磁盘占用分析工具——WizTree
    vite2 打包的时候vendorxxx.js文件过大的解决方法
    nfPress —— 在线文档也可以加载组件和编写代码
    通过UI库深入了解Vue的插槽的使用技巧
    基于 vite2 + Vue3 写一个在线帮助文档工具
    【mysql】sql查看mysql 数据库 数据表 容量大小
  • 原文地址:https://www.cnblogs.com/tun117/p/5407631.html
Copyright © 2020-2023  润新知