Going Home POJ - 2195 (最小费用最大流)

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

思路应该算是这个算法的板子题了,感觉还是只有看自己的代码才是最容易懂的。cap表示边的容量,w表示费用。
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#define fuck(x) cout<<#x<<" = "<<x<<endl;
#define ls (t<<1)
#define rs ((t<<1)+1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1024;
const int inf = 2.1e9;
const ll Inf = 999999999999999999;
const int mod = 1000000007;
const double eps = 1e-6;
const double pi = acos(-1);
int n,m;
char mp[108][108];
struct node
{
    int x,y;
}p1[maxn],p2[maxn];
int Head[maxn],Next[maxn*maxn],v[maxn*maxn],w[maxn*maxn],cap[maxn*maxn],cnt;
int t1,t2;int ans;
void init()
{
    t1=1;cnt=t2=ans=0;
    memset(Head,-1,sizeof(Head));
}

void add(int x,int y,int z,int f){
//    cout<<x<<" "<<y<<" "<<z<<endl;
    v[cnt]=y;
    w[cnt]=z;
    cap[cnt]=f;
    Next[cnt]=Head[x];
    Head[x]=cnt++;

    v[cnt]=x;
    w[cnt]=-z;
    cap[cnt]=0;
    Next[cnt]=Head[y];
    Head[y]=cnt++;
}
bool vis[maxn];
int dis[maxn];
int prevv[maxn],preve[maxn];
int s,t;
bool spfa()
{
    queue<int>q;
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=t;i++){
        dis[i]=inf;
    }

    dis[s]=0;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=false;
        for(int k=Head[u];k!=-1;k=Next[k]){
            if(cap[k]&&dis[v[k]]>dis[u]+w[k]){
                dis[v[k]]=dis[u]+w[k];
                prevv[v[k]]=u;
                preve[v[k]]=k;

                if(!vis[v[k]]){
                    vis[v[k]]=true;
                    q.push(v[k]);
                }
            }
        }
    }
//    for(int i=1;i<=t;i++){
//        cout<<dis[i]<<" ";
//    }
//    cout<<endl;
//    getchar();getchar();
    if(dis[t]==inf){return false;}
    else return true;
}
int min_cost_flow()
{
//    fuck("???")
    while(spfa()){
//        cout<<"____"<<endl;
        for(int i=t;i!=s;i=prevv[i]){
            int k=preve[i];
            cap[k]-=1;
            cap[k^1]+=1;
        }
//        cout<<endl;
        ans+=dis[t];
    }

}

int main()
{
//    ios::sync_with_stdio(false);
//    freopen("in.txt","r",stdin);

    while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){
        init();
        for(int i=1;i<=n;i++){
            scanf("%s",mp[i]+1);
            for(int j=1;j<=m;j++){
                if(mp[i][j]==‘m‘){p1[++t1]=node{i,j};}
                else if(mp[i][j]==‘H‘){p2[++t2]=node{i,j};}
            }
        }
        s=1;t=t1+t2+1;
        for(int i=2;i<=t1;i++){
            add(s,i,0,1);
            for(int j=1;j<=t2;j++){
                add(i,j+t1,abs(p1[i].x-p2[j].x)+abs(p1[i].y-p2[j].y),inf);
            }
        }
        for(int i=1;i<=t2;i++){
            add(i+t1,t,0,1);
        }

        min_cost_flow();
        printf("%d\n",ans);
    }

    return 0;
}

  

 

原文地址:https://www.cnblogs.com/ZGQblogs/p/10177069.html

时间: 2024-08-13 09:18:45

Going Home POJ - 2195 (最小费用最大流)的相关文章

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

POJ - 2195 最小费用最大流

题意:每个人到每个房子一一对应,费用为曼哈顿距离,求最小的费用 题解:单源点汇点最小费用最大流,每个人和房子对于建边 #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #include<iomanip&

poj 2516 最小费用最大流

Language: Default Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 14334   Accepted: 4908 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (m

poj 2135(最小费用最大流)

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14730   Accepted: 5614 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

poj 2135 最小费用最大流初步

这个题的意思是农夫约翰要呆人参观他的农场, 刚开始从1开始走, 走到N后又返回1点, 两次不能走相同的路, 问农夫约翰走的最短的路是多少?? 我们可以用最小MCMF来解决这个问题, 对于图中的每一条边, 我们建立了两条流量为1, 费用为边权的边, 再增加一个源点和一个汇点, 源点指向1, 流量为2,费用为0, N指向汇点, 流量为2费用为0, 然后求出最小费用即可, 代码如下: #include <cstdio> #include <algorithm> #include <

POJ 3680 最小费用最大流

这题来源:<算法竞赛经典入门-训练指南>中的367页:区间k覆盖问题. 思路:这题建图比较机智,我刚开始想到能建的图也就是离散化后两个端点连边,流量为1,费用为负的权值(因为求的是最大费用最大流),然后再加上源点和汇点,也就如此而已:但是这样建图样例第二和第四个不正确,因为中间没有联系的没连边,然后k就没用了. 原来最重要的连边是i和i+1之间的连边,流量为k,费用为0:为什么要连这些边呢,刚开始我也没想明白,后面才知道,因为有的端点之间你要让它们产生联系并且受制与k次,那么就得把这些点都连边

POJ 3422 最小费用最大流

链接: http://poj.org/problem?id=3422 题解: 关键是如何处理"只能获取一次"的问题,为此可以为每个点创建伪点,由两条有向边相连.原始点到伪点连一条容量为1,权值为负分数的边:原始点到伪点连一条容量为无穷,权值为0的边.前者表示分数只能拿一次,后者表示第二次第三次--可以继续走这个点,但是不拿分数.负权是因为题目要求的是"最大费用".又因为最多走同一个点K次,所以此处的无穷大取K就行了. 代码: 1 #include <map&g

POJ 2195:Going Home(最小费用最大流)

http://poj.org/problem?id=2195 题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少. 思路:通过这个题目学了最小费用最大流.最小费用最大流是保证在流量最大的情况下,使得费用最小. 建图是把S->人->家->T这些边弄上形成一个网络,边的容量是1(因为一个人只能和一个家匹配),边的费用是曼哈顿距离,反向边的费用是-cost. 算法的思想大概是通过SPFA找增广路径,并且找的时候费用是可以松弛的.当找到这样一条增

POJ 2195 Going Home (最小费用最大流)

题目链接:http://poj.org/problem?id=2195 题意:n*m的矩阵,地图上有若干个人(m)和房子(H),且人与房子的数量一致.man每移动一格费用为1,一个房子只能住一个人.现在要求所有的人出发,都入住房子,求最少话费. 思路:建立一个超级源点和汇点,源点与人相连费用为0,容量为1,人与房子相连,费用为人与房子的距离,容量为1,房子与汇点相连,费用为0,容量为1 #include <iostream> #include <cstdlib> #include

POJ - 2195 Going Home(最小费用最大流)

1.N*M的矩阵中,有k个人和k个房子,每个人分别进入一个房子中,求所有人移动的最小距离. 2.人看成源点,房子看成汇点,求最小费用最大流. 建图-- 人指向房子,容量为1,费用为人到房子的曼哈顿距离. 建立超级源点和超级汇点:超级源点指向人,容量为1,费用为0:超级汇点指向房子,容量为1,费用为0. 求超级源点到超级汇点的最小费用最大流即可. ps:容量为什么都设为1?---有待研究.. 3. 1.Bellman-Ford: #include<iostream> #include<st