(说明:这个专题中有很多题目也可以运用KM匹配算法。)

 

HDU 1533 Going Home

  入门题,典型二分图最优权值匹配。

  建图:

  1. 超级源点与人连边,流量为1,花费为0;

  2. 房子与超级汇点连边,流量为1,花费为0;

  3. 每个人与每个房子连边,流量为1,花费为距离。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <queue>
#include <cassert>
using namespace std;
#define MP          make_pair
#define PB          push_back
#define F           first
#define S           second
#define pii         pair<int,int>
#define clr(a)      memset((a),0,sizeof (a))
#define rep(i,a,b)  for(int i=(a);i<=(int)(b);i++)
#define per(i,a,b)  for(int i=(a);i>=(int)(b);i--)
#define inf         (0x3f3f3f3f)
#define eps         1e-6
#define MAXN        505
#define MAXM        4000005
#define MODN        1000000007
#define RI(x)       scanf("%d", &x)
#define RII(x,y)    scanf("%d%d", &x, &y)
#define RIII(x,y,z) scanf("%d%d%d", &x, &y, &z)
#define debug       puts("reach here");
typedef long long LL;

struct Edge
{
    int to;
    int vol;
    int cost;
    int next;
}E[MAXM];

int index[MAXN];
int NE;
int pre[MAXN], pos[MAXN];
int dis[MAXN], que[MAXM];
bool vis[MAXN];
int n, m, k;
char g[105][105];
vector<pii> vm, vh;

void add_edge(int from, int to, int vol, int cost)
{
    E[NE].to = to;   E[NE].vol = vol; E[NE].cost = cost;  E[NE].next = index[from]; index[from] = NE++;
    E[NE].to = from; E[NE].vol = 0;   E[NE].cost = -cost; E[NE].next = index[to];   index[to] = NE++;
}

bool spfa(int s, int t)
{
    memset(pre, -1, sizeof(pre));
    memset(vis, 0, sizeof(vis));
    int head, tail; head = tail = 0;
    memset(dis, 0x3f, sizeof dis);
    que[tail++] = s;
    pre[s] = s;
    dis[s] = 0;
    vis[s] = 1;
    while(head != tail)
    {
        int cur = que[head++];
        vis[cur] = 0;
        for(int i = index[cur]; i != -1; i = E[i].next)
        {
            int adj = E[i].to;
            if(E[i].vol > 0 && dis[cur] + E[i].cost < dis[adj])
            {
                dis[adj] = dis[cur] + E[i].cost;
                pre[adj] = cur;
                pos[adj] = i;
                if(!vis[adj])
                {
                    vis[adj] = 1;
                    que[tail++] = adj;
                }
            }
        }
    }
    return pre[t] != -1;
}

int MinCostMaxFlow(int s, int t)
{
    int cost = 0;
    int flow = 0;
    while(spfa(s, t))
    {
        int f = inf;
        for(int i = t; i != s; i = pre[i])
            if (E[pos[i]].vol < f) f = E[pos[i]].vol;
        flow += f; cost += dis[t] * f;
        for(int i = t; i != s; i = pre[i])
        {
            E[pos[i]].vol -= f;
            E[pos[i] ^ 1].vol += f;
        }
    }
    return cost;
}

void init()
{
    NE = 0;
    memset(index, -1, sizeof index);
}

int main()
{
    while(RII(n, m) != EOF)
    {
        if(n == 0 && m == 0) break;
        vm.clear(); vh.clear();
        rep(i,0,n-1)
        {
            scanf("%s", g[i]);
            rep(j,0,m-1)
                if(g[i][j] == 'm')
                    vm.PB(MP(i,j));
                else if(g[i][j] == 'H')
                    vh.PB(MP(i,j));
        }
        int s = 0, t = vm.size() + vh.size() + 1;
        int m = vm.size();
        init();
        rep(i,0,m-1)
        {
            add_edge(0, 1+i, 1, 0);
            rep(j,0,vh.size()-1)
                add_edge(1+i, 1+m+j, 1, abs(vm[i].F - vh[j].F)+abs(vm[i].S-vh[j].S));
        }
        rep(j,0,vh.size()-1)
            add_edge(1+m+j, t, 1, 0);
        printf("%d\n", MinCostMaxFlow(s,t));
    }
}
View Code

相关文章: