1. 程式人生 > >poj2195 Going Home(費用流|KM)

poj2195 Going Home(費用流|KM)

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

分析:
很顯然的費用流,
只要處理出任意一對小人和房子之間的曼哈頓距離就好了
這裡寫圖片描述

這裡寫程式碼片
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include<cmath>

using namespace std;

const int INF=1000010;
struct node{
    int x,y,v,cost,next;
};
node way[40040];
char ch[101][101],c;
int n,m,s,e,tt,tot,toto;
int st[10010],home[5010][2],man[5010][2];
bool p[10010];
int pre[10010],d[10010];

int ab(int x)
{
    if (x>=0) return x;
    else return -x;
}

void add(int u,int w,int z,int co)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].cost=co;way[tot].next=st[u];st[u]=tot;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].v=0;way[tot].cost=-co;way[tot].next=st[w];st[w]=tot;
    return;
}

bool spfa()
{
    int i;
    memset(p,1,sizeof(p));
    memset(d,0x7f,sizeof(d));
    memset(pre,0,sizeof(pre));
    queue<int> q;
    p[s]=0;
    d[s]=0;
    q.push(s);
    while (!q.empty())
    {
        int r=q.front();
        q.pop();
        for (i=st[r];i!=-1;i=way[i].next)
        {
            if (way[i].v&&d[way[i].y]>d[r]+way[i].cost)
            {
                d[way[i].y]=d[r]+way[i].cost; 
                pre[way[i].y]=i;
                if (p[way[i].y])
                {
                    q.push(way[i].y);
                    p[way[i].y]=0;
                }
            }
        }
        p[r]=1;
    }
    return d[e]<0x7f;
}

int doit()
{
    int ans=0,sum,i;
    while (spfa())
    {
        sum=INF;
        for (i=e;i!=s;i=way[pre[i]].x)
            sum=min(sum,way[pre[i]].v);
        ans+=sum*d[e];
        for (i=e;i!=s;i=way[pre[i]].x)
        {
            way[pre[i]].v-=sum;
            way[pre[i]^1].v+=sum;
        }
    }
    return ans;
}

int main()
{
    scanf("%d%d%c",&n,&m,&c);
    while (n&&m)
    {
        tt=toto=0;
        tot=-1;
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=m;j++)
            {
                scanf("%c",&ch[i][j]);
                if (ch[i][j]=='H')
                {
                    tt++;
                    home[tt][0]=i; home[tt][1]=j;
                }
                else if (ch[i][j]=='m')
                {
                    toto++;
                    man[toto][0]=i;
                    man[toto][1]=j;
                }
            }
            scanf("%c",&c);
        }
        memset(st,-1,sizeof(st));
        s=0;
        e=2*tt+1;
        for (int i=1;i<=tt;i++)
        {
           add(0,i,1,0);
           add(i+tt,e,1,0);
           for (int j=1;j<=tt;j++)
           {
                int r=ab(man[i][0]-home[j][0])+ab(man[i][1]-home[j][1]);
                add(i,j+tt,1,r);
           }
        }
        printf("%d\n",doit());
        scanf("%d%d%c",&n,&m,&c);
    }
    return 0;
} 

還有一種KM做法,因為KM是求最大權完美匹配的
所以所有的邊權*-1

時間上是網路流的十分之一
這裡寫圖片描述

tip

這道題要用G++交(很迷)

//這裡寫程式碼片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int INF=0x33333333;
int Lx[110],Ly[110],slack[110],W[110][110];
bool L[110],R[110];
int man[110][2],hou[110][2],tt1,tt2,belong[110],n,m;
char s[110];

int abs(int x){if (x>0) return x;else return -x;}

int match(int i,int n)
{
    L[i]=1;
    for (int j=1;j<=n;j++)
        if (!R[j])
        {
            int v=Lx[i]+Ly[j]-W[i][j];
            if (!v)
            {
                R[j]=1;
                if (!belong[j]||match(belong[j],n))
                {
                    belong[j]=i;
                    return 1;
                }
            }
            else slack[j]=min(slack[j],v);
        }
    return 0;
}

int KM()
{
    int n=tt1;
    memset(belong,0,sizeof(belong));
    for (int i=1;i<=n;i++)
    {
        Ly[i]=0;
        Lx[i]=W[i][1];
        for (int j=2;j<=n;j++)
            Lx[i]=max(Lx[i],W[i][j]);
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=n;j++) slack[j]=INF;
        while (1)
        {
            memset(L,0,sizeof(L));
            memset(R,0,sizeof(R));
            if (match(i,tt1)) break;
            int a=INF;
            for (int j=1;j<=n;j++)
                if (!R[j]) a=min(slack[j],a);
            for (int j=1;j<=n;j++)
                if (L[j]) Lx[j]-=a;
            for (int j=1;j<=n;j++)
                if (R[j]) Ly[j]+=a;
                else slack[j]-=a;
        }
    }
    int ans=0;
    for (int i=1;i<=n;i++) ans+=W[belong[i]][i];
    return -ans;
}

int main()
{
    scanf("%d%d",&n,&m);
    while (n&&m)
    {
        tt1=tt2=0;
        for (int i=1;i<=n;i++)
        {
            scanf("%s",s);
            for (int j=0;j<m;j++)
                if (s[j]=='H') hou[++tt2][0]=i,hou[tt2][1]=j+1;
                else if (s[j]=='m') man[++tt1][0]=i,man[tt1][1]=j+1;
        }
        for (int i=1;i<=tt1;i++)
            for (int j=1;j<=tt2;j++)
                W[i][j]=-(abs(man[i][0]-hou[j][0])+abs(man[i][1]-hou[j][1]));
        printf("%d\n",KM());
        scanf("%d%d",&n,&m);
    }
}

相關推薦

poj2195 Going Home費用|KM

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

POJ 2195 Going Home費用

void 個人 nod const 移動 方向 push class main http://poj.org/problem?id=2195 題意: 在一個網格地圖上,有n個小人和n棟房子。在每個時間單位內,每個小人可以往水平方向或垂直方向上移動一步,走到相鄰的方格中。

Going Home 費用

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

POJ2195 Going Home 最小費最大||二分圖最大權匹配

Going Home 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 horizontal

POJ 2195 Going Home網路-費用

Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 17777 Accepted: 9059 Description On a grid map there are n

Going Home網路 最小費用最大

Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22035 Accepted: 11139 Description On a grid map there are n l

2195 Going Home 網路最小

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 ver

HDU-1533 Going Home二分圖匹配

最近開始做最小費用流的題目,該題是二分圖完美匹配下的最小權匹配,所謂完美匹配就是說從源點流入的總流量等於從匯點流出的總流量,在這種狀態下的最小費用 。  那麼顯然是要套用最小費用流模板,另外二分圖匹配的第一步就是要劃分集合,劃分兩個集合,集合A與源點相連,集合B與匯點相連,

HDU 6445 2018CCPC網路賽1008 Search for Answer費用 + 構圖

大致題意:給你一個競賽圖,告訴你一個記數方法,也即所有邊同向的四元組加一,所有相鄰兩邊方向相反的四元組減一。現在讓你最大化這個結果。 說實話,不看題解應該很難想到是一個費用流……題解給的也真是簡單,個人感覺還可能有錯? 我們可以這麼考慮,觀察它給的計數演算

POJ2195Going Home最小費用最大

POJ2195:Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26210   A

POJ 2195-Going HomeKM演算法/最小費用最大演算法

Going Home Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 21730 Accepted: 10990 Description On a grid map there are n

Going Home最小費用最大

Going Home http://poj.org/problem?id=2195 Time Limit: 1000MS   Memory Limit: 65536K Total Submi

POJ 2195 Going Home最小費用最大題解

題意:給你一張圖,有k個人和k個房子,每個房子只能住一個人,每個人到某一房子的花費為曼哈頓距離,問你讓k個人怎麼走,使他們都住房子且花費最小。 思路:我們把所有人和超級源點相連,流量為1花費為0,所有房子和超級匯點相連,流量為1花費為0,然後把所有人和所有房子加邊,流量為1

POJ 2195 Going Home 最小費用最大

題目連結 第一次寫最小費用最大流 最小費用最大流相當於最短路和最大流的結合,建立了殘量圖後,費用作為距離 然後bfs遍歷源點到匯點的最小費用,用陣列記錄遍歷路徑,而後通過最大流的做法 對殘量圖進行更新,尋找路徑中的最小流量得到的就是最小費用最大流。 題

2195 Going Home 最小費用最大

Going HomeTime Limit: 1000MSMemory Limit: 65536KTotal Submissions: 24299Accepted: 12196DescriptionOn a grid map there are n little men and

HDU 1533 Going HomeKM完美匹配

pro min msu max tle scanf size dfs using HDU 1533 Going Home 題目鏈接 題意:就是一個H要相應一個m,使得總曼哈頓距離最小 思路:KM完美匹配,因為是要最小。所以邊權建負數來處理就可以

POJ2195:Going Home (最小費用最大)

Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 26212   Accepted:

POJ2195 Going Home 最小費用最大

Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 25567 Accepted: 12838 Description On a grid map there are

POJ 2195 Going Home最小權匹配、KM演算法

題目連結: POJ 2195 Going Home 題意: 給出一個r*c的矩陣,字母H代表房屋,字母m代表客人,房屋的數量和客人的數量相同。每間房只能住一個人。求這些客人全部住進客房的最少移動步數? #include <cstdio>

poj2195 Going Home,最小費用最大

題意: 給定一個N*M的地圖,地圖上有若干個man和house,且man與house的數量一致。man每移動一格需花費$1(即單位費用=單位距離),一間house只能入住一個man。現在要求所有的man都入住house,求最小費用。 分析: 二分圖的最大匹配 我採用的是