zoukankan      html  css  js  c++  java
  • (网络流 匹配 KM) Going Home --poj -- 2195

    链接:

    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
    ", 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
    ", MinCost());
        }
    
        return 0;
    }
    勿忘初心
  • 相关阅读:
    redis哨兵高可用
    数据库主从搭建
    docker 补充
    docker 进阶操作
    docker 简介
    数据可视化(Matplotlib)
    数据操作
    pandas练习
    Pandas简介
    python mysql utf-8 latin
  • 原文地址:https://www.cnblogs.com/YY56/p/4728036.html
Copyright © 2011-2022 走看看