POJ 2195 Going Home 最小费用最大流

来源:互联网 发布:等离子切割机编程方法 编辑:程序博客网 时间:2024/04/29 21:10

第二道费用流的题目,这道题目的建图还是很简单的啊,抽象出来一个超级源点,一个超级汇点。然后从每个人到房子的距离为花费,然后容量为1,建图。一开始在建图的问题上没太想明白、、、感觉就得这么建图,好像也是蒙对了啊。后来LYN给我点播了一下。一开始我是考虑到一个房子会有对应多个人的情况,然后想不明白怎么处理这些会有冲突的情况。后来想到了,spfa的时候就会把最优的一种情况先选出来。然后就是次优的情况了啊、所以不会再出现我担心的那种重复了啊。而且会更新流量,相当于标记过了做过的路径。所以就可以了啊。就是典型的最小费用最大流问题。

原来这道题目也可以用二分图的最大权匹配来做,下面是,从宝哥那里搞来的模版,写的啊。

Going Home
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 16555 Accepted: 8471

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.mH.5 5HH..m...............mm..H7 8...H.......H.......H....mmmHmmmm...H.......H.......H....0 0

Sample Output

21028
#include <algorithm>#include <iostream>#include <stdlib.h>#include <string.h>#include <iomanip>#include <stdio.h>#include <string>#include <queue>#include <cmath>#include <stack>#include <map>#include <set>#define eps 1e-7//#define M 1000100//#define LL __int64#define LL long long#define INF 0x3f3f3f3f#define PI 3.1415926535898const int maxn = 1100;using namespace std;int c[maxn][maxn];//流量限制;int dis[maxn];//最短路径int w[maxn][maxn];//费用;int visit[maxn];//标记;int path[maxn];//记录路径;int f[maxn][maxn];//最大流量限制;int S,T;//超级汇点与源点;char str[maxn][maxn];int sum;struct node{    int x, y;} H[maxn], M[maxn];int spfa(){    int i;    queue<int> q;    for(i = 0; i <= T; i++)    {        visit[i] = 0;        path[i] = -1;        dis[i] = INF;    }    dis[S] = 0;    q.push(S);    visit[S] = 1;    while(!q.empty())    {        int u = q.front();        q.pop();        visit[u] = 0;        for(int v = 1; v <= T; v++)        {            if(c[u][v] > f[u][v] && dis[v] > dis[u]+w[u][v])            {                path[v] = u;                dis[v] = dis[u]+w[u][v];                if(!visit[v])                {                    visit[v] = 1;                    q.push(v);                }            }        }    }    if(path[T] == -1)        return 0;    return 1;}void find_max_road(){    while(spfa())//每次spfa求出一条增广路    {        int _max = INF;        int pre = T;        while(path[pre] != -1)        {            _max = min(_max, c[path[pre]][pre]-f[path[pre]][pre]);            pre = path[pre];        }        pre = T;        while(pre != -1)//更新流量        {            f[path[pre]][pre] += _max;            f[pre][path[pre]] = -f[path[pre]][pre];            pre = path[pre];        }    }}int main(){    int n, m;    while(cin >>n>>m)    {        if(!n && !m)            break;        sum = 0;        for(int i = 0; i < n; i++)            cin >>str[i];        int t1 = 0;        int t2 = 0;        memset(w , 0 , sizeof(w));        memset(c , 0 , sizeof(c));        memset(f , 0 , sizeof(f));        for(int i = 0; i < n; i++)            for(int j = 0; j < m; j++)            {                if(str[i][j] == 'm')                {                    M[++t1].x = i;                    M[t1].y = j;                }                else if(str[i][j] == 'H')                {                    H[++t2].x = i;                    H[t2].y = j;                }            }        for(int i = 1; i <= t1; i++)        {            for(int j = t1+1; j <= 2*t1; j++)            {                w[i][j] = abs(H[i].x-M[j-t1].x)+abs(H[i].y-M[j-t1].y);                w[j][i] = -w[i][j];                c[i][j] = 1;            }        }        S = 0;        T = 2*t1+1;        for(int i = 1; i <= t1; i++)        {            w[S][i] = 0;            c[S][i] = 1;        }        for(int j = t1+1; j <= 2*t1; j++)        {            w[j][T] = 0;            c[j][T] = 1;        }        find_max_road();        for(int i = 1; i <= t1; i++)            for(int j = 1; j <= t2; j++)            {                sum += f[i][j+t1]*w[i][j+t1];            }        cout<<sum<<endl;    }    return 0;}

KM算法:

#include <algorithm>#include <iostream>#include <stdlib.h>#include <string.h>#include <iomanip>#include <stdio.h>#include <string>#include <queue>#include <cmath>#include <stack>#include <map>#include <set>#define eps 1e-7#define M 1000100//#define LL __int64#define LL long long#define INF 0x3f3f3f3f#define PI 3.1415926535898const int maxn = 110;using namespace std;struct node{    int x, y;} p[100*maxn], h[100*maxn];int link[maxn], w[110][110];int lx[maxn], ly[maxn];//记录顶标;int slack[maxn];bool vtx[maxn], vty[maxn];int nx, ny, n, m;char str[110][110];bool dfs(int i){    int j;    vtx[i] = true;    for(j = 0; j < ny; j++)    {        if(vty[j]) continue;        int tmp = lx[i] + ly[j] - w[i][j];        if(tmp == 0)        {            vty[j] = true;            if(dfs(link[j]) || link[j] == -1)            {                link[j] = i;                return true;            }        }        else            slack[j] = min(tmp, slack[j]);    }    return false;}int KM(){    for(int i = 0; i < nx; i++)    {        lx[i] = -INF;        for(int j = 0 ; j < ny; j++)        {            lx[i] = max(lx[i], w[i][j]);        }    }    memset(link , -1 , sizeof(link));    memset(ly , 0 , sizeof(ly));    for(int i = 0; i < nx; i++)    {        for(int j = 0; j < ny; j++)            slack[j] = INF;        while(1)        {            memset(vtx , false , sizeof(vtx));            memset(vty , false , sizeof(vty));            if(dfs(i))                break;            int d = INF;            for(int j = 0; j < ny; j++)            {                if(!vty[j] && d > slack[j])                    d = slack[j];            }            if(d == INF) return -1;            for(int j = 0; j < nx; j++)                if(vtx[j])                    lx[j] -= d;            for(int j = 0; j < ny; j++)            {                if(vty[j])                    ly[j] += d;                else                    slack[j] -= d;            }        }    }    int sum = 0;    for(int i = 0; i < ny; i++)    {        if(link[i] > -1)            sum += w[link[i]][i];    }    return sum;}int main(){    while(cin >>n>>m)    {        if(!n && !m)            break;        nx = ny = 0;        for(int i = 0; i < n; i++)        {            cin >>str[i];            for(int j = 0; j < m; j++)            {                if(str[i][j] == 'm')                {                    p[nx].x = i;                    p[nx++].y = j;                }                else if(str[i][j] == 'H')                {                    h[ny].x = i;                    h[ny++].y = j;                }            }        }        for(int i = 0; i < nx; i++)            for(int j = 0; j < ny; j++)                w[i][j] = -INF;        for(int i = 0; i < nx; i++)            for(int j = 0; j < ny; j++)                w[i][j] = -(abs(p[i].x - h[j].x) + abs(p[i].y - h[j].y));        cout<<-KM()<<endl;    }    return 0;}


0 0
原创粉丝点击