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#include #include 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 q; for(int i=0; i 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 0&&(n||m)){ for(int i=0; i