poj 2195 Going Home(KM||费用流)

来源:互联网 发布:mac 文件共享 灰色 编辑:程序博客网 时间:2024/06/05 19:48

http://poj.org/problem?id=2195


题目大意:

给定一个N*M的地图,地图上有一定数量的m(代表人)和H(代表房子),两者数量相等;

要求求出把所有m移动到H的位置上总距离最小为多少;


思路:

用最优二分匹配或者最小费用最大流都能做,觉得用最优二分匹配会简单一些;

建图把m和H分别作为二分图的两个顶点集合vx和vy,求出两两之间的距离,用km算法求出最优匹配;

要注意的是,要求距离的最短,而km求的是最大匹配值,所以建图的时候距离要取反;


这是KM做的,费用流做的在下面;

#include<iostream>#include<cmath>using namespace std;const int MAX=105;const int inf=1<<30;int n,lack;int map[MAX][MAX]; char maps[MAX][MAX];int dx[MAX],dy[MAX]; int link[MAX];bool visx[MAX],visy[MAX]; bool DFS(int v){    visx[v]=true;    for(int i=0;i<n;i++)    {        if(visy[i])            continue;        int t=dx[v]+dy[i]-map[v][i];        if(!t)        {            visy[i]=true;            if(link[i]==-1||DFS(link[i]))            {                link[i]=v;                return true;            }        }        else             if(t<lack)                lack=t;    }    return false;}void KM(){    int i,j;    memset(dx,0,sizeof(dx));    memset(dy,0,sizeof(dy));    memset(link,-1,sizeof(link));    for(i=0;i<n;i++)    {        for(j=0;j<n;j++)            if(map[i][j]>dx[i])                dx[i]=map[i][j];    }    for(i=0;i<n;i++)    {        while(true)        {            memset(visx,0,sizeof(visx));            memset(visy,0,sizeof(visy));            lack=0x7fffffff;            if(DFS(i))                break;            for(j=0;j<n;j++)            {                if(visx[j])                    dx[j]-=lack;                if(visy[j])                    dy[j]+=lack;            }        }    }}int main(int i,int j,int k,int l){    int row,col,ans,numi,numj;    while(scanf("%d%d",&row,&col)&&(row+col))    {/*Initial*/        n=ans=numi=numj=0;        memset(link,-1,sizeof(link));        memset(map,0,sizeof(map));/*Input*/        for(i=0;i<row;i++)        {            scanf("%*c");            for(j=0;j<col;j++)            {                scanf("%c",&maps[i][j]);                if(maps[i][j]=='m')                    n++;            }        }/*Structure Graph*//*±ßȨֵ±äΪ¸ºÈ¨£¬Çó³ö×î´óÆ¥ÅäÖµ¼´Îª×îС¾àÀë×ܺÍ*/        for(i=0;i<row;i++)         {            for(j=0;j<col;j++)            {                if(maps[i][j]=='m')                {                    for(k=0;k<row;k++)                    {                        for(l=0;l<col;l++)                        {                            if(maps[k][l]=='H')                                map[numi][numj++]=-(abs(k-i)+abs(l-j)); //±ßΪ¸ºÈ¨Öµ                        }                    }                    numi++;                    numj=0;                }            }        }        KM();        int ans=0;            for(i=0;i<n;i++)        {            if(link[i]!=-1)                ans+=map[link[i]][i];        }        printf("%d\n",-ans);    }    return 0;}


-------------------------------------------------华丽的分割线------------------------------------------

#include<iostream>#include<queue>#include<cmath>#include<cstring>using namespace std;const int inf=1<<30;const int N=100500;const int M=200500;class Edge{public:int u;int v;int cost;int flow;int next;}edge[M<<3];class Node{public:int x;int y;}man[105],house[105];int s,t;int edge_num;int max_flow;int head[N];int pre[N];int dist[N];bool vis[N];char map[105][105];void addedge(int u,int v,int cost,int flow){edge[edge_num].u=u;edge[edge_num].v=v;edge[edge_num].flow=flow;edge[edge_num].cost=cost;edge[edge_num].next=head[u];head[u]=edge_num++;edge[edge_num].u=v;edge[edge_num].v=u;edge[edge_num].flow=0;edge[edge_num].cost=-cost;edge[edge_num].next=head[v];head[v]=edge_num++;return ;}/*SPFA 对费用求最短路*/bool spfa(){queue <int> que;memset(pre,-1,sizeof(pre));memset(vis,false,sizeof(vis));for(int j=0;j<=t;j++)dist[j]=inf;dist[s]=0;vis[s]=true;que.push(s);while(!que.empty()){int x=que.front();que.pop();int y;for(int i=head[x];~i;i=edge[i].next){y=edge[i].v;if(edge[i].flow && dist[y]>dist[x]+edge[i].cost){dist[y]=dist[x]+edge[i].cost;pre[y]=i;if(!vis[y]){vis[y]=true;que.push(y);}}}vis[x]=false;}if(dist[t]==inf)return false;return true;}void argument_flow(){int v,alfa=inf; for(v=pre[t];~v;v=pre[ edge[v].u ]){if(alfa>edge[v].flow)alfa=edge[v].flow;}for(v=pre[t];~v;v=pre[ edge[v].u ]){edge[v].flow -= alfa;edge[v^1].flow += alfa;}max_flow += alfa*dist[t];}int main(int i,int j){int n,m;while(~scanf("%d %d",&n,&m)&&n&&m){edge_num=0;max_flow=0;s=0;t=n*m+1;memset(head,-1,sizeof(head));int p=0;int q=0;/*Input & Structure Graph*/for(i=1;i<=n;i++){scanf("%s",map[i]+1);for(j=1;j<=m;j++){int x=(i-1)*m+j;if(map[i][j]=='m'){addedge(s,x,0,1);man[++p].x=i;//储存人的坐标man[p].y=j;}if(map[i][j]=='H'){addedge(x,t,0,1);house[++q].x=i;//储存房子的坐标house[q].y=j;}}}for(i=1;i<=p;i++){/*人和房子之间连边*/for(j=1;j<=q;j++)addedge(man[i].x*m+man[i].y-m,house[j].x*m+house[j].y-m,abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y),1);}while(spfa())argument_flow();printf("%d\n",max_flow);}return 0;}



原创粉丝点击