N*M图里有x个人x个房间,让每个人进到任意一个房间,一个房间只能容纳一个人,可以经过房间的位置却不进入。每个人都会找个房间进入,求他们走的路程和最短
最小费用流,建图:
源点 对每个人建边 容量为1,费用0,同理房间对汇点容量1,费用0,人和房间容量为1,费用为最小距离(就是x1-x2+y1-y2)。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define eps 10^(-6)
#define Q_CIN ios::sync_with_stdio(false)
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define CLR( a , x ) memset ( a , x , sizeof (a) )
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define MOD 10009
#define NMAX 10002
#define min(a,b) ((a)>(b)?(b):(a))
#define max(a,b) ((a)<(b)?(b):(a))
const int inf=0x3f3f3f3f;
const int maxn=103*2;
int ss,tt;
int cap[maxn][maxn],dis[maxn],pre[maxn],inq[maxn],low[maxn],cost[maxn][maxn];
char mp[maxn/2][maxn/2];
struct What{
int x,y;
}man[maxn/2],house[maxn/2];
void init()
{
CLR(pre,-1);
CLR(dis,inf);
CLR(inq,0);
CLR(low,inf);
}
int spfa(int s,int t)
{
queue<int>q;
q.push(s);
pre[s]=-1;
init();
inq[s]=1;
dis[s]=0;
while(!q.empty()){
int u=q.front();q.pop();inq[u]=0;
FOR(i,ss,tt){
if(cap[u][i]&&dis[i]>dis[u]+cost[u][i]){
dis[i]=dis[u]+cost[u][i];
pre[i]=u;
low[i]=min(low[u],cap[u][i]);
if(!inq[i]){
q.push(i);
inq[i]=1;
}
}
}
}
return dis[t]!=inf;
}
int mincost(int s,int t)
{
int mincost=0;
while(spfa(s,t)){
int u=t;
while(pre[u]!=-1){
cap[pre[u]][u]-=low[t];
cap[u][pre[u]]+=low[t];
u=pre[u];
}
mincost+=dis[t];
}
return mincost;
}
int main()
{
// freopen("1.in","r",stdin);
int m,n;
while(cin>>n>>m,m||n){
CLR(cap,0);
CLR(cost,inf);
int manNum=1,houseNum=1;
FOR(i,1,n)
FOR(j,1,m){
cin>>mp[i][j];
if(mp[i][j]=='m'){
man[manNum].x=i;
man[manNum].y=j;
manNum++;
}
else if(mp[i][j]=='H'){
house[houseNum].x=i;
house[houseNum].y=j;
houseNum++;
}
}
int k1=manNum-1;
FOR(i,1,k1){
FOR(j,k1+1,k1*2){
cost[i][j]=abs(man[i].x-house[j-k1].x)+abs(man[i].y-house[j-k1].y);
cost[j][i]=-cost[i][j];
cap[i][j]=1;
// cap[j][i]=0;
}
}
ss=0,tt=k1*2+1;
FOR(i,1,k1)
cost[ss][i]=cost[i][ss]=0,cap[ss][i]=1;
FOR(i,k1+1,k1*2)
cost[i][tt]=cost[tt][i]=0,cap[i][tt]=1;
cout<<mincost(ss,tt)<<endl;
}
return 0;
}
套KM算法的话就是模板了(快过网络流)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
const int N = 310;
const int INF = 0x3f3f3f3f;
int nx, ny; //两边的点数
int g[N][N];//二分图描述
int linker[N], lx[N], ly[N]; //y中各点匹配状态,x,y中的点标号
int slack[N];
bool visx[N], visy[N];
bool DFS(int x) {
visx[x] = true;
for (int y = 0; y < ny; y++) {
if (visy[y]) {
continue;
}
int tmp = lx[x] + ly[y] - g[x][y];
if (tmp == 0) {
visy[y] = true;
if (linker[y] == -1 || DFS(linker[y])) {
linker[y] = x;
return true;
}
} else if (slack[y] > tmp) {
slack[y] = tmp;
}
}
return false;
}
int KM() {
memset(linker, -1, sizeof(linker));
memset(ly, 0, sizeof(ly));
for (int i = 0; i < nx; i++) {
lx[i] = -INF;
for (int j = 0; j < ny; j++)
if (g[i][j] > lx[i]) {
lx[i] = g[i][j];
}
}
for (int x = 0; x < nx; x++){
for (int i = 0; i < ny; i++) {
slack[i] = INF;
}
while (true) {
memset(visx, false, sizeof(visx));
memset(visy, false, sizeof(visy));
if (DFS(x)) {
break;
}
int d = INF;
for (int i = 0; i < ny; i++)
if (!visy[i] && d > slack[i]) {
d = slack[i];
}
for (int i = 0; i < nx; i++)
if (visx[i]) {
lx[i] -= d;
}
for (int i = 0; i < ny; i++) {
if (visy[i]) {
ly[i] += d;
} else {
slack[i] -= d;
}
}
}
}
int res = 0;
for (int i = 0; i < ny; i++)
if (linker[i] != -1) {
res += g[linker[i]][i];
}
return res;
}
char mp[105][105];
struct What{
int x,y;
}man[105],house[105];
int main()
{
// freopen("1.in","r",stdin);
int m,n;
while(cin>>n>>m,m||n){
int manNum=0,houseNum=0;
REP(i,n)
REP(j,m){
cin>>mp[i][j];
if(mp[i][j]=='m'){
man[manNum].x=i;
man[manNum].y=j;
manNum++;
}
else if(mp[i][j]=='H'){
house[houseNum].x=i;
house[houseNum].y=j;
houseNum++;
}
}
int k1=manNum;
REP(i,k1)
REP(j,k1){
g[i][j]=-(abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y));
}
nx=ny=k1;
cout<<-KM()<<endl;
}
return 0;
}