poj2195 going home最小费用流

来源:互联网 发布:软件供应商排行 编辑:程序博客网 时间:2024/05/16 00:24
/*
    题目描述:题目给出一张n*m的地图,图中 . 表示空格,m表示人,H表示房间,人和房间的数量相同,人每移动一格的长度是1,现要求每个人进到
    一间房中,使房间和人一一对应起来,问所有人最小的移动距离是多少。
    
    方法:先用迪杰斯特拉预处理出每个人到每间房的距离;
            再利用最小费用流,总共分四列:
            第一列是源节点,连向所有的人,容量为1,费用为0;
            第二列是人,从人连向每一间房,容量为1,费用为人到每间房的距离;
            第三列是房间,每间房连向汇节点,容量为1,费用为0;
            第四列为汇节点;
            求出最小费用流即为答案。
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
int num = 0;
const int inf = 1000000000;
const int maxn =  100 + 5;
const int maxs = 10000 + 5;
int n,m;
int dis[maxn][maxn],id[maxn][maxn];
char mp[maxn][maxn];
typedef long long ll;
struct Edge
{
    int from,to,cap,flow,cost;
};
struct MCMF
{
    int n,m,s,t;
    vector<Edge>edges;
    vector<int>G[maxs];
    int d[maxs],p[maxs],a[maxs],inq[maxs];


    void init(int n)
    {
        this -> n = n;
        for(int i=0;i<=n;i++)       G[i].clear();
        edges.clear();
    }




    void AddEdge(int from,int to,int cap,int cost)
    {
        Edge e1 = {from , to , cap , 0 , cost};
        Edge e2 = {to , from , 0 ,  0 , -cost};
        edges.push_back(e1);
        edges.push_back(e2);
        int m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }




    bool BellmanFord(int s,int t,int &flow , ll& cost)
    {
        for(int i=0;i<=n;i++){
            d[i] = inf;
        }
        d[s] = 0;   p[s] = 0;    a[s] = inf;
        mem(inq,0);     inq[s] = 1;
        queue<int>Q;
        Q.push(s);
        while(!Q.empty()){
            int x = Q.front();      Q.pop();
            inq[x] = 0;
            for(int i= 0;i<G[x].size();i++){
                Edge &e  =  edges[G[x][i]];
                if(e.cap>e.flow && d[e.to]>d[x]+e.cost){
                    d[e.to] = d[x] + e.cost;
                    p[e.to] = G[x][i];
                    a[e.to] = min(a[x],e.cap - e.flow);
                    if(!inq[e.to]){
                        Q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
        if(d[t]==inf)       return false;
        flow += a[t];
        cost += (ll)a[t]*(ll)d[t];
        int u = t;
        while(u!=s){
            edges[p[u]].flow += a[t];
            edges[p[u]^1].flow -= a[t];
            u = edges[p[u]].from;
        }
        return true;
    }




    ll Mincost(int s,int t,int & flow)
    {
        flow = 0;
        ll cost = 0;
        while(BellmanFord(s,t,flow,cost))       ;
        return cost;
    }


};
MCMF g;
struct edge
{
    int from , to , dist;
};
struct HeapNode
{
    int u,d;
    bool operator < (const HeapNode&rhs)const
    {
        return d>rhs.d;
    }
};
struct Dijkstra
{
    int n,m,s,t;
    int d[maxs],p[maxs],vis[maxs];
    vector<int>G[maxs];
    vector<edge>edges;


    void init(int n)
    {
        this -> n = n;
        for(int i=0;i<=n;i++){
            G[i].clear();
        }
        edges.clear();
    }


    void AddEdge(int from,int to,int dist)
    {
        edge e = {from,to,dist};
        edges.push_back(e);
        int m = edges.size();
        G[from].push_back(m-1);
    }


    void dijkstra(int s)
    {
        for(int i=0;i<=n;i++)       d[i] = inf;
        priority_queue<HeapNode>Q;
        HeapNode st = {s,0};
        d[s] = 0;
        mem(vis,0);
        Q.push(st);
        while(!Q.empty()){
            HeapNode t = Q.top();
            Q.pop();
            int x = t.u;
            if(vis[x])      continue;
            vis[x] = 1;
            for(int i=0;i<G[x].size();i++){
                edge &e = edges[G[x][i]];
                if(d[e.to]>d[x]+e.dist){
                    d[e.to] = d[x] + e.dist;
                    p[e.to] = G[x][i];
                    HeapNode nt;
                    nt = {e.to,d[e.to]};
                    Q.push(nt);
                }
            }
        }
    }
};
Dijkstra g2;
bool valid(int x,int y)
{
    if(x<1||x>n||y<1||y>m)
        return false;
    return true;
}
int drx[]= {-1,1,0,0};
int dry[]={0,0,-1,1};
vector<int>house;
vector<int>man;
int main()
{
    while(scanf("%d %d",&n,&m)!=EOF&&n){
        for(int i=1;i<=n;i++)       scanf("%s",mp[i]+1);
        mem(id,0);
        house.clear();
        man.clear();
        g2.init(n*m);
        for(int i=1;i<=n;i++){
            for(int j = 1;j<=m;j++){
                id[i][j] = (i - 1)*m + j;
                if(mp[i][j]=='H')
                    house.push_back(id[i][j]);
                if(mp[i][j]=='m')
                    man.push_back(id[i][j]);
            }
        }
        for(int i = 1;i<=n;i++){
            for(int j = 1;j<=m;j++){
                for(int k = 0;k<4;k++){
                    int nx = i + drx[k];
                    int ny = j + dry[k];
                    if(valid(nx,ny))
                        g2.AddEdge(id[i][j],id[nx][ny],1);
                }
            }
        }
        int len = man.size();
        g.init(2*len + 1);
        for(int i=0;i<len;i++){
            int x = man[i];
            g2.dijkstra(x);
            for(int j = 0;j<len;j++){
                int y = house[j];
                g.AddEdge( i + 1 ,len + j + 1 , 1 , g2.d[y] );
            }
        }
        int source = 0,sink = 2*len + 1;
        for(int i=0;i<len;i++){
            g.AddEdge( source , i+1 , 1 , 0);
            g.AddEdge(len + i + 1,sink , 1 ,0);
        }
        int flow;
        ll ans = g.Mincost(source,sink,flow);
        printf("%lld\n",ans);
    }
    return 0;
}
0 0