POJ 2195 Going Home

题目大意:

给你n个房子和n个人,每个人要住一间房子。每个人到房子有一个距离。求所有人都有房子,并且所走的总距离是最小的。
================================================
二分图KM:
 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const int INF = 1e9+7;
const int maxn = 105;
const int MOD = 1e9+7;
struct node
{
    int x, y;
    node (int x=0,int y=0): x(x), y(y) {}
} Man[maxn], House[maxn];
int Lx[maxn], Ly[maxn], G[maxn][maxn], P[maxn], k, d;///可行性顶标
bool vx[maxn], vy[maxn];
char maps[maxn][maxn];

bool Find(int u)
{
    vx[u] = true;
    for(int i=0; i<k; i++)
    {
        if(!vy[i] && Lx[u] + Ly[i] == G[u][i])
        {
            vy[i] = true;
            if(P[i] == -1 || Find(P[i]) )
            {
                P[i] = u;
                return true;
            }
        }
        if(!vy[i])
            d = min(d, Lx[u] + Ly[i] - G[u][i]);
    }
    return false;
}

int solve()
{
    memset(P, -1, sizeof(P));
    for(int i=0; i<k; i++)
    {
        while(1)
        {
            memset(vx, false, sizeof(vx));
            memset(vy, false, sizeof(vy));
            d = INF;
            if( Find(i) )
                break;

            for(int j=0; j<k; j++)
            {
                if(vx[j]) Lx[j] -= d;
                if(vy[j]) Ly[j] += d;
            }
        }
    }
    int ans = 0;
    for(int i=0; i<k; i++)
        ans += G[P[i]][i];
    return abs(ans);
}

int Len(node A, node B)
{
    return  abs(A.x - B.x) + abs(A.y - B.y);
}

int main()
{
    int n, m, k1, k2;///n*m的矩阵有k个房子

    while(scanf("%d %d",&n, &m), n+m)
    {
        k1 = k2 = 0;
        memset(Lx, 0, sizeof(Lx));
        memset(Ly, 0, sizeof(Ly));
        for(int i=0; i<n; i++)
        {
            scanf("%s", maps[i]);
            for(int j=0; j<m; j++)
            {
                if(maps[i][j] == 'H')
                    House[k1 ++] = node(i,j);
                if(maps[i][j] == 'm')
                    Man[k2 ++] = node(i,j);
            }
        }
        k = k1;
        for(int i=0; i<k; i++)
        for(int j=0; j<k; j++)
            G[i][j] = -Len(House[i],Man[j]);

        int ans = solve();
        printf("%d\n", ans);
    }
    return 0;
}
/*
5 5
HH..m
.....
.....
.....
mm..H

*/

===========================================================================================================

网络流

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
typedef long long LL;
const int INF = 1e9+7;
const int maxn = 2005;
const int MOD = 1e9+7;
/**最小费用最大流*/
struct Point
{
    int x, y;
    Point(int x=0,int y=0): x(x), y(y) {}
}Man[maxn], House[maxn];
struct Map
{
    int flow, cost;
    Map(int flow=0,int cost=0):flow(flow), cost(cost) {}
}G[maxn][maxn];
int dist[maxn], Pre[maxn], k;
bool vis[maxn];
char maps[maxn][maxn];

int Len(Point A,Point B)
{
    return abs(A.x-B.x) + abs(A.y-B.y);
}
bool Spfa(int Star,int End)
{
    for(int i=0; i <= End; i++)
        dist[i] = INF;
    dist[Star] = 0;
    memset(Pre, 0, sizeof(Pre));
    memset(vis, false, sizeof(vis));
    queue<int> Q;
    Q.push(Star);
    vis[Star] = true;
    while(Q.size())
    {
        int u = Q.front();
        Q.pop();
        vis[u] = false;

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

                dist[i] = dist[u]+G[u][i].cost;
                if(!vis[i])
                {
                    vis[i] = true;
                    Q.push(i);
                }

            }
        }
    }
    return dist[End] != INF;
}

int solve(int Star,int End)
{
    int cost = 0;

    while( Spfa(Star, End) )
    {
        for(int i=End; i!= Star; i=Pre[i])
        {
            cost += G[Pre[i]][i].cost;
            G[Pre[i]][i].flow -= 1;
            G[i][Pre[i]].flow += 1;
        }
    }
    return cost;
}

int main()
{
    int n, m;
    while(scanf("%d %d",&n, &m),n+m)
    {
        memset(G, 0,sizeof(G));
        int k1 = 0, k2 = 0;
        for(int i=0; i<n; i++)
        {
            scanf("%s", maps[i]);
            for(int j=0; j<m; j++)
            {
                if(maps[i][j] == 'H')
                    House[k1++] = Point(i,j);
                if(maps[i][j] == 'm')
                    Man[k2++] = Point(i,j);
            }
        }
        int Star = 0, End = 2*k1+1;

        for(int i=1; i<=k1; i++)///建立源点到人的边
            G[0][i] = Map(1, 0);

        for(int i=1; i<=k1; i++)///建立人到房子
        for(int j=k1+1; j<=2*k1; j++)
        {
            G[i][j] = Map(1, Len(Man[i-1], House[j-k1-1]));
            G[j][i].cost = -G[i][j].cost;
        }


        for(int i=k1+1; i<=2*k1; i++)///建立房子到汇点的边
            G[i][End] = Map(1, 0);

        printf("%d\n", solve(Star, End));

    }
    return 0;
}

 

posted @ 2015-10-08 11:49  向前走丶不回首  阅读(143)  评论(0编辑  收藏  举报