2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
2 10 28
题意:给一个地图,标了人m和房H的位置,人数和房子数量相等,现在所有人要回各自的家,一个房只能容一个人。问所有人走的步数总和最少是多少?每一步只能走相邻的格子。
解题:最小费用流。
分3类点:1:源点S,汇点T。 2:人M。3:房H。
建图:(u , v , cap, cost):u-->v边容为cap,花费为cost
1):(S , M , 1 , 0)
2):(M , H , 1 , mindis):mindis表示人到房的最短距离
3:(H , T , 1 , 0)
#include<stdio.h> #include<string.h> #include<queue> using namespace std; const int MAXN = 10010; const int MAXM = 100100; const int INF = 1<<30; struct EDG{ int to,next,cap,flow; int cost; //单价 }edg[MAXM]; int head[MAXN],eid; int pre[MAXN], cost[MAXN] ; //点0~(n-1) void init(){ eid=0; memset(head,-1,sizeof(head)); } void addEdg(int u,int v,int cap,int cst){ edg[eid].to=v; edg[eid].next=head[u]; edg[eid].cost = cst; edg[eid].cap=cap; edg[eid].flow=0; head[u]=eid++; edg[eid].to=u; edg[eid].next=head[v]; edg[eid].cost = -cst; edg[eid].cap=0; edg[eid].flow=0; head[v]=eid++; } bool inq[MAXN]; bool spfa(int sNode,int eNode,int n){ queue<int>q; for(int i=0; i<n; i++){ inq[i]=false; cost[i]= INF; } cost[sNode]=0; inq[sNode]=1; pre[sNode]=-1; q.push(sNode); while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=0; for(int i=head[u]; i!=-1; i=edg[i].next){ int v=edg[i].to; if(edg[i].cap-edg[i].flow>0 && cost[v]>cost[u]+edg[i].cost){ //在满足可增流的情况下,最小花费 cost[v] = cost[u]+edg[i].cost; pre[v]=i; //记录路径上的边 if(!inq[v]) q.push(v),inq[v]=1; } } } return cost[eNode]!=INF; //判断有没有增广路 } //反回的是最大流,最小花费为minCost int minCost_maxFlow(int sNode,int eNode ,int& minCost,int n){ int ans=0; while(spfa(sNode,eNode,n)){ int mint=INF; for(int i=pre[eNode]; i!=-1; i=pre[edg[i^1].to]){ if(mint>edg[i].cap-edg[i].flow) mint=edg[i].cap-edg[i].flow; } ans+=mint; for(int i=pre[eNode]; i!=-1; i=pre[edg[i^1].to]){ edg[i].flow+=mint; edg[i^1].flow-=mint; minCost+=mint*edg[i].cost; } } return ans; } int abs(int a){ return a>0?a:-a; } int buildGraph(char mapt[105][105],int n,int m){ int id[105][105] , k=1 ; for(int i=0; i<n; i++) for(int j=0; j<m; j++) if(mapt[i][j]=='H'||mapt[i][j]=='m') id[i][j]=k++; int s=0 , t = k; for(int i=0; i<n; i++) for(int j=0; j<m; j++) if(mapt[i][j]=='m'){ int u,v; u=id[i][j]; addEdg(s,u,1,0); for(int ti=0; ti<n; ti++) for(int tj=0; tj<m; tj++) if(mapt[ti][tj]=='H'){ v=id[ti][tj]; addEdg(u,v,1,abs(ti-i)+abs(tj-j)); } } else if(mapt[i][j]=='H') addEdg(id[i][j],t,1,0); return k; } int main(){ int n,m; char mapt[105][105]; while(scanf("%d%d",&n,&m)>0&&(n||m)){ for(int i=0; i<n; i++) scanf("%s",mapt[i]); init(); int s=0,t=buildGraph(mapt,n,m) , minCost=0; minCost_maxFlow(s,t,minCost,t+1); printf("%d\n",minCost); } }
原文地址:http://blog.csdn.net/u010372095/article/details/46611007