链接:

 

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82835#problem/D

 

有n个人有n栋房子,每栋房子里能进一个人,但每走一格的价值是1, 所以要尽可能的少走,这一看很显然是匹配用KM算法,

但这是网络流专题的,不是太懂怎么用网络流来写

 

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

#define N 110
#define INF 0x3fffffff

struct node{int x, y, step;};

char G[N][N];
int n, m1, dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int STEP[N][N], m[N][N], H[N][N], vis[N][N];
int  num1, num2, lx[N], ly[N];
int  used[N], visx[N], visy[N], s[N];


void BFS(node p)
{
    node q, t;
    queue<node>Q;
    Q.push(p);

    memset(vis, 0, sizeof(vis));
    vis[p.x][p.y] = 1;

    while(Q.size())
    {
        q = Q.front(); Q.pop();

        if(G[q.x][q.y]=='H')
            STEP[m[p.x][p.y]][H[q.x][q.y]] = -q.step;

        for(int i=0; i<4; i++)
        {
            t.x = q.x + dir[i][0];
            t.y = q.y + dir[i][1];
            t.step = q.step + 1;

            if(t.x>=0 && t.x<n && t.y>=0 && t.y<m1 && !vis[t.x][t.y])
            {
                Q.push(t);
                vis[t.x][t.y] = 1;
            }
        }
    }
}
bool Find(int u)
{
    visx[u] = 1;
    for(int i=1; i<=num2; i++)
    {
        if(!visy[i] && lx[u]+ly[i]==STEP[u][i])
        {
            visy[i] = 1;
            if(!used[i] || Find(used[i]))
            {
                used[i] = u;
                return true;
            }
        }
        else
            s[i] = min(s[i], lx[u]+ly[i]-STEP[u][i]);
    }
    return false;
}
void KM()
{
    memset(used, 0, sizeof(used));
    memset(lx, 0, sizeof(lx));
    memset(ly, 0, sizeof(ly));

    for(int i=1; i<=num1; i++)
    for(int j=1; j<=num2; j++)
        lx[i] = max(lx[i], STEP[i][j]);

    for(int i=1; i<=num1; i++)
    {
        for(int j=1; j<=num2; j++)
            s[j] = INF;
        while(1)
        {
            memset(visx, 0, sizeof(visx));
            memset(visy, 0, sizeof(visy));

            if(Find(i))
                break;

            int d = INF;
            for(int j=1; j<=num2; j++)
                if(!visy[j])
                d  = min(d, s[j]);

            for(int j=1; j<=num2; j++)
            {
                if(visx[j])
                    lx[j] -= d;
                if(visy[j])
                    ly[j] += d;
            }
        }
    }
    int res = 0;

    for(int i=1; i<=num1; i++)
        res -= STEP[used[i]][i];

    printf("%d\n", res);
}

int main()
{
    while(scanf("%d%d", &n, &m1), n+m1)
    {
        int i, j;
        node p;

        num1=0, num2=0;
        memset(STEP, 0, sizeof(STEP));
        for(i=0; i<n; i++)
        {
            scanf("%s", G[i]);
            for(j=0; j<m1; j++)
            {
                if(G[i][j]=='m')
                    m[i][j] = ++num1;
                if(G[i][j]=='H')
                    H[i][j] = ++num2;
            }
        }

        for(i=0; i<n; i++)
        for(j=0; j<m1; j++)
        {
            if(G[i][j]=='m')
            {
                p.x=i, p.y=j, p.step=0;
                BFS(p);
            }
        }

        KM();
    }
    return 0;
}

 

粘个别人的代码:

#include<stdio.h>
#include<string.h>
#include<queue>
#include<stack>
#include<algorithm>
#include<math.h>
using namespace std;

const int MAXN = 407;
const int oo = 1e9+7;

struct point{int x, y;}man[MAXN], house[MAXN];
struct Graph{int flow, cost;}G[MAXN][MAXN];
int NX, NY, start, End;///男人和房子的数目,源点和汇点

bool spfa(int pre[])
{
    stack<int> sta;
    int instack[MAXN]={0}, dist[MAXN];

    for(int i=1; i<=End; i++)
        dist[i] = oo;

    dist[start] = 0;
    sta.push(start);

    while(sta.size())
    {
        int u = sta.top();sta.pop();
        instack[u] = false;

        for(int i=1; i<=End; i++)
        {
            if(G[u][i].flow &&  dist[i] > dist[u]+G[u][i].cost)
            {
                dist[i] = dist[u] + G[u][i].cost;
                pre[i] = u;

                if(instack[i] == false)
                {
                    sta.push(i);
                    instack[i] = true;
                }
            }
        }
    }

    return dist[End] != oo;
}
int MinCost()
{
    int i, pre[MAXN], cost=0;

    while(spfa(pre) == true)
    {///如果有增广路
        int MinFlow = oo;

        for(i=End; i != start; i=pre[i])
            MinFlow = min(MinFlow, G[pre[i]][i].flow);
        for(i=End; i != start; i=pre[i])
        {///逆向访问这条增广路上的每条边
            int k = pre[i];
            G[k][i].flow -= MinFlow;
            G[i][k].flow += MinFlow;
            cost += G[k][i].cost;
        }
    }

    return cost;
}

int main()
{
    int M, N;

    while(scanf("%d%d", &M, &N), M+N)
    {
        int i, j;char s[MAXN][MAXN];

        memset(G, 0, sizeof(G));
        NX = NY = 0;

        for(i=0; i<M; i++)
            scanf("%s", s[i]);

        for(i=0; i<M; i++)
        for(j=0; j<N; j++)
        {
            if(s[i][j] == 'm')
            {
                NX++;
                man[NX].x = i;
                man[NX].y = j;
            }
            if(s[i][j] == 'H')
            {
                NY++;
                house[NY].x = i;
                house[NY].y = j;
            }
        }

        for(i=1; i<=NX; i++)
        for(j=1; j<=NY; j++)
        {///房子的编号从NX~NX+NY
            G[i][NX+j].flow = 1;
            G[i][NX+j].cost = fabs(man[i].x-house[j].x)+fabs(man[i].y-house[j].y);
            G[NX+j][i].cost = -G[i][NX+j].cost;
        }

        start = NX+NY+1, End = start+1;

        for(i=1; i<=NX; i++)
        {///把源点与人连接
            G[start][i].flow = 1;
            G[start][i].cost = 0;
        }
        for(i=1; i<=NY; i++)
        {///把房子和汇点连接
            G[NX+i][End].flow = 1;
            G[NX+i][End].cost = 0;
        }

        printf("%d\n", MinCost());
    }

    return 0;
}

 

posted on 2015-08-13 17:47  栀蓝  阅读(185)  评论(0编辑  收藏  举报

levels of contents