hdoj 1533

Going Home

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

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

这是一道最小距离最大流的例题,重点在构图,下面是两个算法,第一个是我自己写的,另一个是我参考的,目前我还属于半懂不懂,就不写题解了哈,下附代码

#include<iostream>
#include<cstring>
#include<climits>
#include<queue>
#include<cstdio>
using namespace std;
int abss(int a,int b)
{
    if(a>b)return a-b;
    else return b-a;
}
struct MCMF
{
    int cap,lf,flow,cost;
}G[210][210];
char map[110][110];
int pre[210],dis[210];
bool isq[210];
struct House
{
    int x,y;
}house[110];
struct Man
{
    int x,y;
}man[110];
int n,m,home,people,all;
void init()
{
    home=people=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>map[i][j];
            if(map[i][j]==‘m‘)
            {
                man[++people].x=i;
                man[people].y=j;
            }
            else if(map[i][j]==‘H‘)
            {
                house[++home].x=i;
                house[home].y=j;
            }
        }
    }
    all=people+home+1;
    memset(G,0,sizeof(G));
    for(int i=1;i<=people;i++)
    {
        G[0][i].cap=G[0][i].lf=1;
        for(int j=1;j<=home;j++)
        {
            G[i][j+people].cost=abss(man[i].x,house[j].x)+abss(man[i].y,house[j].y);
            G[j+people][i].cost=-G[i][j+people].cost;
            G[i][j+people].cap=G[i][j+people].lf=1;
        }
        G[i+people][all].cap=G[i+people][all].lf=1;
    }
}
void spfa(int s)
{
    memset(pre,-1,sizeof(pre));
    int temp;
    for(int i=0;i<=all;i++)
    {
        dis[i]=(i==s?0:INT_MAX);
        isq[i]=false;
    }
    queue<int>q;
    q.push(s);
    isq[s]=true;
    while(!q.empty())
    {
        temp=q.front();
        isq[temp]=false;
        q.pop();
        for(int i=0;i<=all;i++)
        {
            if(G[temp][i].lf&&G[temp][i].cost+dis[temp]<dis[i])
            {
                dis[i]=G[temp][i].cost+dis[temp];
                pre[i]=temp;
                if(!isq[i])
                {
                    q.push(i);
                    isq[i]=true;
                }
            }
        }
    }
}
void mcmf(int s,int t)
{
    spfa(s);
    int sum=0;
    while(pre[t]!=-1)
    {
        int min=INT_MAX;
        for(int i=t;pre[i]!=-1;i=pre[i])
            min=min<G[pre[i]][i].lf?min:G[pre[i]][i].lf;
        sum+=dis[t];
        for(int i=t;pre[i]!=-1;i=pre[i])
        {
            G[pre[i]][i].lf-=min;
            G[i][pre[i]].lf+=min;
        }
        spfa(s);
    }
    cout<<sum<<endl;
}
int main()
{
    while(~scanf("%d%d",&n,&m),n+m)
    {
        init();
        mcmf(0,all);
    }
    return 0;
}
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<climits>
#include<algorithm>
#include<queue>
using namespace std;

int n,m;
const int N=250;
const int M=10000;
const int MAX=0xffffff;
char coord[N][N];//坐标集
int pre[M];//存储前驱顶点
int dist[M];//存储到源点s的距离

int inq[M];//每个顶点是否在队列中的标志
int min_c_f;//记录增广路径中的残留容量
int vertex;//顶点数
int sum;//保存最小费用

struct element
{
    int c;//容量
    int f;//流
    int c_f;//残留容量
    int v;//价值
} G[N][N];

struct man//记录小矮人的坐标
{
    int x,y;
} man[N];
struct house//记录房子的坐标
{
    int x,y;
} house[N];

void init()
{
    sum=0;
    int mcase,hcase;//记录有多少个小矮人和房子
    mcase=hcase=0;
    for(int i=1; i<=m; i++)//输入过程
    {
        for(int j=1; j<=n; j++)
        {
            cin>>coord[i][j];
            if(coord[i][j]==‘m‘)//记录小矮人的坐标
            {
                mcase++;
                man[mcase].x=i;
                man[mcase].y=j;
            }
            if(coord[i][j]==‘H‘)//记录房子的坐标
            {
                hcase++;
                house[hcase].x=i;
                house[hcase].y=j;
            }
        }
    }

    vertex=mcase+hcase+1;//加入超源点0和超汇点,注意要+1,即抽象成网络流的结构
    for(int u=0; u<=vertex; u++)//初始流为0,所以不用重构W(f);
    {
        for(int v=0; v<=vertex; v++)
        {
            G[u][v].c=G[v][u].c=0;
            G[u][v].c_f=G[v][u].c_f=0;
            G[u][v].f=G[v][u].f=0;
            G[u][v].v=G[v][u].v=MAX;
        }
    }

    for(int i=1; i<=mcase; i++)
    {
        G[0][i].v=0;//从超源点到各个小矮人之间的权值取为0
        G[0][i].c=G[0][i].c_f=1;//从超源点到各个小矮人之间的容量取为1
        for(int j=1; j<=hcase; j++)
        {
            int w=abs(house[j].x-man[i].x)+abs(house[j].y-man[i].y);//计算小矮人到每一个房子之间的距离
            G[i][mcase+j].v=w;//将距离赋给对应的权值,注意第二个下标,即表示房子的下标为mcase+j~!!
            G[i][mcase+j].c=1;//容量取为1
            G[i][mcase+j].c_f=G[i][mcase+j].c;
            G[mcase+j][vertex].v=0;//将从各个房子到超汇点之间的权值取为0,注意房子的下标为mcase+j
            G[mcase+j][vertex].c=G[mcase+j][vertex].c_f=1;//将从各个房子到超汇点之间的容量取为0,注意房子的下标为mcase+j
        }
    }
}

void SPFA(int s)//求最短路径的SPFA算法
{
    queue<int> Q;
    int u;
    for(int i=0; i<=vertex; i++)//初始化
    {
        dist[i]=MAX;
        pre[i]=-1;
        inq[i]=0;
    }
    dist[s]=0;
    Q.push(s);
    inq[s] = 1;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();
        inq[u]=0;
        for(int i=0; i<=vertex; i++)//更新u的邻接点的dist[], pre[], inq[]
        {
            int v=i;
            if(G[u][v].c_f==0)     // 表示(u,v)没有边
                continue;
            if(G[u][v].v==MAX)
                G[u][v].v=-G[v][u].v;
            if(dist[v]>dist[u]+G[u][v].v)//松弛操作
            {
                dist[v]=dist[u]+G[u][v].v;
                pre[v]=u;
                if(inq[v]==0)
                {
                    Q.push(v);
                    inq[v]=1;
                }
            }
        }
    }
}

void ford_fulkerson(int s,int t)
{
    SPFA(s);
    while(pre[t]!=-1)//pre为-1表示没有找到从s到t的增广路径
    {
        //cout<<dist[t]<<"^_^"<<endl;
        sum+=dist[t];//将这一条最短路径的值加进sum
        min_c_f=MAX;
        int u=pre[t], v=t;//计算增广路径上的残留容量
        while(u!=-1)
        {
            if(min_c_f > G[u][v].c_f)
                min_c_f=G[u][v].c_f;
            v=u;
            u=pre[v];
        }
        u=pre[t], v=t;
        while(u!=-1)
        {
            G[u][v].f+=min_c_f; //修改流
            G[v][u].f=-G[u][v].f;
            G[u][v].c_f=G[u][v].c-G[u][v].f; //修改残留容量
            G[v][u].c_f=G[v][u].c-G[v][u].f;
            v=u;
            u=pre[v];
        }
        SPFA(s);
    }
}

int main()
{
    while(cin>>m>>n,m||n)
    {
        init();
        ford_fulkerson(0,vertex);//计算从超源点0到超汇点vertex之间的最小费用最大流
        cout<<sum<<endl;
    }
    return 0;
}
时间: 2024-10-01 23:53:42

hdoj 1533的相关文章

最大流增广路(KM算法) HDOJ 1533 Going Home

题目传送门 1 /* 2 最小费用流:KM算法是求最大流,只要w = -w就可以了,很经典的方法 3 */ 4 #include <cstdio> 5 #include <cmath> 6 #include <algorithm> 7 #include <cstring> 8 using namespace std; 9 10 const int MAXN = 1e2 + 10; 11 const int INF = 0x3f3f3f3f; 12 int x

hdoj 1533 Going Home 【最小费用最大流】【KM入门题】

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3443    Accepted Submission(s): 1763 Problem Description On a grid map there are n little men and n houses. In each unit time, every

【HDOJ】4328 Cut the cake

将原问题转化为求完全由1组成的最大子矩阵.挺经典的通过dp将n^3转化为n^2. 1 /* 4328 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector>

POJ Xiangqi 4001 &amp;&amp; HDOJ 4121 Xiangqi

题目链接(POJ):http://poj.org/problem?id=4001 题目链接(HDOJ):http://acm.hdu.edu.cn/showproblem.php?pid=4121 Xiangqi Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1108   Accepted: 299 Description Xiangqi is one of the most popular two-player boa

【HDOJ】4956 Poor Hanamichi

基本数学题一道,看错位数,当成大数减做了,而且还把方向看反了.所求为最接近l的值. 1 #include <cstdio> 2 3 int f(__int64 x) { 4 int i, sum; 5 6 i = sum = 0; 7 while (x) { 8 if (i & 1) 9 sum -= x%10; 10 else 11 sum += x%10; 12 ++i; 13 x/=10; 14 } 15 return sum; 16 } 17 18 int main() { 1

HDOJ 4901 The Romantic Hero

DP....扫两遍组合起来 The Romantic Hero Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 547    Accepted Submission(s): 217 Problem Description There is an old country and the king fell in love with a

【HDOJ】1099 Lottery

题意超难懂,实则一道概率论的题目.求P(n).P(n) = n*(1+1/2+1/3+1/4+...+1/n).结果如果可以除尽则表示为整数,否则表示为假分数. 1 #include <cstdio> 2 #include <cstring> 3 4 #define MAXN 25 5 6 __int64 buf[MAXN]; 7 8 __int64 gcd(__int64 a, __int64 b) { 9 if (b == 0) return a; 10 else return

【HDOJ】2844 Coins

完全背包. 1 #include <stdio.h> 2 #include <string.h> 3 4 int a[105], c[105]; 5 int n, m; 6 int dp[100005]; 7 8 int mymax(int a, int b) { 9 return a>b ? a:b; 10 } 11 12 void CompletePack(int c) { 13 int i; 14 15 for (i=c; i<=m; ++i) 16 dp[i]

HDOJ 3790 双权值Dijkstra

1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <cstring> 5 using namespace std; 6 7 const int INF = 1000000; 8 const int MAXSIZE = 1005; 9 10 int map[MAXSIZE][MAXSIZE]; 11 int price[MAXSIZE][MAXSIZE]; 1