给出一个n*m的图,其中m是人,H是房子,.是空地,满足人的个数等于房子数。
现在让每个人都选择一个房子住,每个人只能住一间,每一间只能住一个人。
每个人可以向4个方向移动,每移动一步需要1$,问所有人移动到房子里的最少花费。
其中,n,m<=100,最多有100个人。
最小给用流裸题。
建立一个超级源点,跟每一个房子连一条边,容量为1,花费为0
每一个人与超级汇点连一条边,容量为1,花费为0
一个房子与每一个人建一条边,房子指向人,容量为1,花费用2者的距离(不是直线距离)
然后跑最小费用流算法就可以了。
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 6 using namespace std; 7 8 const int maxn=205; 9 const int inf=0x3f3f3f3f; 10 const int s=0; 11 int t; 12 int tot; 13 char maze[maxn]; 14 char str[maxn][maxn]; 15 bool vis[maxn]; 16 int dis[maxn]; 17 int prev[maxn]; 18 int pree[maxn]; 19 20 struct Point 21 { 22 int x,y; 23 }; 24 Point point[maxn]; 25 struct Edge 26 { 27 int to,cap,cost,rev; 28 }; 29 vector<Edge>edge[maxn]; 30 31 inline int get_abs(int tmp) 32 { 33 if(tmp>0) 34 return tmp; 35 return -tmp; 36 } 37 38 inline int min(int x,int y) 39 { 40 return x<y?x:y; 41 } 42 43 inline int get_dis(int i,int j) 44 { 45 return get_abs(point[i].x-point[j].x)+get_abs(point[i].y-point[j].y); 46 } 47 48 void addedge(int from,int to,int cap,int cost) 49 { 50 edge[from].push_back((Edge){to,cap,cost,edge[to].size()}); 51 edge[to].push_back((Edge){from,0,-cost,edge[from].size()-1}); 52 } 53 54 void build_graph(int n,int m) 55 { 56 //要从0开始 57 for(int i=0;i<maxn;i++) 58 edge[i].clear(); 59 tot=1; 60 for(int i=1;i<=n;i++) 61 { 62 for(int j=1;j<=m;j++) 63 { 64 if(str[i][j]=='H') 65 { 66 point[tot].x=i; 67 point[tot++].y=j; 68 } 69 } 70 } 71 for(int i=1;i<=n;i++) 72 { 73 for(int j=1;j<=m;j++) 74 { 75 if(str[i][j]=='m') 76 { 77 point[tot].x=i; 78 point[tot++].y=j; 79 } 80 } 81 } 82 t=tot; 83 tot--; 84 tot/=2; 85 for(int i=1;i<=tot;i++) 86 { 87 addedge(s,i,1,0); 88 addedge(i+tot,t,1,0); 89 } 90 for(int i=1;i<=tot;i++) 91 { 92 for(int j=tot+1;j<=tot*2;j++) 93 { 94 addedge(i,j,1,get_dis(i,j)); 95 } 96 } 97 } 98 99 void spfa() 100 { 101 memset(vis,false,sizeof vis); 102 for(int i=0;i<=t;i++) 103 dis[i]=inf; 104 queue<int>que; 105 while(!que.empty()) 106 que.pop(); 107 que.push(s); 108 dis[s]=0; 109 vis[s]=true; 110 while(!que.empty()) 111 { 112 int u=que.front(); 113 que.pop(); 114 vis[u]=false; //要记得这步 115 for(int i=0;i<edge[u].size();i++) 116 { 117 Edge &e=edge[u][i]; 118 if(e.cap>0&&dis[e.to]>dis[u]+e.cost) 119 { 120 dis[e.to]=dis[u]+e.cost; 121 prev[e.to]=u; 122 pree[e.to]=i; 123 if(!vis[e.to]) 124 { 125 vis[e.to]=true; 126 que.push(e.to); 127 } 128 } 129 } 130 } 131 return ; 132 } 133 134 int solve() 135 { 136 int ret=0; 137 int flow=tot; 138 while(flow>0) 139 { 140 spfa(); 141 int f=flow; 142 for(int i=t;i!=s;i=prev[i]) 143 { 144 f=min(f,edge[prev[i]][pree[i]].cap); 145 } 146 flow-=f; 147 ret+=dis[t]*f; 148 for(int i=t;i!=s;i=prev[i]) 149 { 150 Edge &e=edge[prev[i]][pree[i]]; 151 e.cap-=f; 152 edge[e.to][e.rev].cap+=f; 153 } 154 } 155 return ret; 156 } 157 158 int main() 159 { 160 int n,m; 161 while(~scanf("%d%d",&n,&m)) 162 { 163 if(!n&&!m) 164 break; 165 for(int i=1;i<=n;i++) 166 { 167 scanf("%s",str[i]+1); 168 } 169 build_graph(n,m); 170 printf("%d ",solve()); 171 } 172 return 0; 173 }