zoukankan      html  css  js  c++  java
  • hdu 1533(最小费用最大流)

    Going Home

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 4223    Accepted Submission(s): 2178


    Problem Description
    On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man.

    Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.

    You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
     
    Input
    There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.
     
    Output
    For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.
     
    Sample Input
    2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
     
    Sample Output
    2 10 28
     
    Source
     
    题意:在一个n*m的矩阵里面有一些人和一些房屋,这些人都要到其中一个房屋里面去,一个人到一个房屋的费用为两者之间的曼哈顿距离,问所有的人和房子配对所需的最小花费?
    题解:最小费用最大流模板题,也可以用KM算法,建图容量就是房屋和人之间的连一条为1的边,花费就是两者之间曼哈顿距离.建立源点和汇点,源点与人之间连一条容量1,费用0的边,房屋与汇点类似,跑一遍最小费用最大流即可。
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    using namespace std;
    const int INF = 999999999;
    const int N = 205; ///most 100 person and house
    const int M = N*N*2;
    struct Edge{
        int u,v,cap,cost,next;
    }edge[M];
    int head[N],tot,low[N],pre[N];
    int total ;
    bool vis[N];
    void addEdge(int u,int v,int cap,int cost,int &k){
        edge[k].u=u,edge[k].v=v,edge[k].cap = cap,edge[k].cost = cost,edge[k].next = head[u],head[u] = k++;
        edge[k].u=v,edge[k].v=u,edge[k].cap = 0,edge[k].cost = -cost,edge[k].next = head[v],head[v] = k++;
    }
    void init(){
        memset(head,-1,sizeof(head));
        tot = 0;
    }
    bool spfa(int s,int t,int n){
        memset(vis,false,sizeof(vis));
        for(int i=0;i<=n;i++){
            low[i] = (i==s)?0:INF;
            pre[i] = -1;
        }
        queue<int> q;
        q.push(s);
        while(!q.empty()){
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int k=head[u];k!=-1;k=edge[k].next){
                int v = edge[k].v;
                if(edge[k].cap>0&&low[v]>low[u]+edge[k].cost){
                    low[v] = low[u] + edge[k].cost;
                    pre[v] = k; ///v为终点对应的边
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        if(pre[t]==-1) return false;
        return true;
    }
    int MCMF(int s,int t,int n){
        int mincost = 0,minflow,flow=0;
         while(spfa(s,t,n))
        {
            minflow=INF+1;
            for(int i=pre[t];i!=-1;i=pre[edge[i].u])
                minflow=min(minflow,edge[i].cap);
            flow+=minflow;
            for(int i=pre[t];i!=-1;i=pre[edge[i].u])
            {
                edge[i].cap-=minflow;
                edge[i^1].cap+=minflow;
            }
            mincost+=low[t]*minflow;
        }
        total=flow;
        return mincost;
    }
    int n,m,a,b;
    char graph[N][N];
    struct House{
        int x,y;
    }h[N];
    struct Person{
        int x,y;
    }p[N];
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF,n+m){
            init();
            a=0,b=0;
            for(int i=0;i<n;i++){
                scanf("%s",graph[i]);
                for(int j=0;j<m;j++){
                    if(graph[i][j]=='H'){
                        h[++a].x = i,h[a].y = j;
                    }
                    if(graph[i][j]=='m'){
                        p[++b].x = i,p[b].y = j;
                    }
                }
            }
            int src = 0,des = a+b+1;
            for(int i=1;i<=a;i++){
                for(int j=1;j<=b;j++){
                    int D = abs(h[i].x-p[j].x)+abs(h[i].y-p[j].y);
                    addEdge(i,j+a,1,D,tot);
                }
            }
            for(int i=1;i<=a;i++){
                addEdge(src,i,1,0,tot);
            }
            for(int i=1;i<=b;i++){
                addEdge(i+a,des,1,0,tot);
            }
            int mincost = MCMF(src,des,a+b+2);
            printf("%d
    ",mincost);
        }
        return 0;
    }
  • 相关阅读:
    UVALive 6044(双连通分量的应用)
    hdu 3760(2次bfs求最短路)
    zoj 3370(二分+二分图染色)
    sgu 326(经典网络流构图)
    hdu 4291(矩阵+暴力求循环节)
    uva 11381(神奇的构图、最小费用最大流)
    hdu 4685(匹配+强连通分量)
    hdu 4496(并查集)
    hdu 4722(记忆化搜索)
    Linux安装Nginx使用负载均衡
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5727559.html
Copyright © 2011-2022 走看看