搞了四五天的费用流,期间断断续续的,直到今天还差几题没A掉的。
题意:
在一个矩阵中,有n间房子和n个人。现在要让这个n个人都到n间房间去。人每走一步就花费为1,问你最小花费为多少?
一个格子可以容纳无限个人;
一个人走到一个房间所在的格子,可以选择不进去。
思路:
相邻的格子间连容量无限的边,费用为1;
源点s连到每个人,容量为1, 费用为0;
房间连到汇点t,容量为1, 费用为0。
构图完成,跑最小费用最大流算法即可得出答案。
代码:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <vector>
#define debug cout<<"??"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e4 + 5;
const int MAXEDGE = 5*1e5 + 5;
int n, m;
struct CEdge
{
int from, to, cap, flow, cost, next;
}edge[MAXEDGE];
struct CMinCost
{
int pp, s, t;
int head[MAXN], d[MAXN]; //array d: save the cost; array head: adjacent edge table;
int a[MAXN], p[MAXN]; //array a: save the flow; array p: save the parent;
bool inq[MAXN]; //array inq: mark if ponint in queue;
CMinCost(int ss, int tt)
{
pp = 0;
s = ss, t = tt;
memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int cap, int cost)
{
edge[pp] = (CEdge){u, v, cap, 0, cost, head[u]};
head[u] = pp++;
edge[pp] = (CEdge){v, u, 0, 0, -cost, head[v]};
head[v] = pp++;
}
bool bellmanFord(int &flow, int &cost)
{
for(int i = 0;i < n*m + 5; i++) d[i] = INF;
memset(inq, false, sizeof(inq));
d[s] = 0, a[s] = INF, inq[s] = true, p[s] = 0;//keep
queue <int> q;
q.push(s);
//bellmanFord
while(!q.empty())
{
int u = q.front(); q.pop();
inq[u] = false;
int next = head[u];
//cout<<next<<endl;
while(next != -1)
{
CEdge &e = edge[next];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost)
{
d[e.to] = d[u] + e.cost;
p[e.to] = next;
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]) { q.push(e.to); inq[e.to] = true; }
}
next = e.next;
}
}
/*cout<<"test://"<<endl;
for(int i = 0;i < n*m+2;i++)
{
cout<<d[i]<<" ";
}
puts("");*/
if(d[t] == INF) return false;
//debug;
flow += a[t];
cost += d[t] * a[t];
int u = t;
while(u != s)
{
edge[p[u]].flow += a[t];
edge[p[u]^1].flow -= a[t];
u = edge[p[u]].from;
}
}
int getMinCost()
{
int cost = 0, flow = 0;
while(bellmanFord(flow, cost));
return cost;
}
};
int main()
{
while(scanf("%d%d",&n, &m), n&&m)
{
getchar();
int s = 0, t = n*m + 1;
CMinCost mc(s, t);
char ch;
for(int i = 0;i < n; i++)
{
for(int j = 1;j <= m; j++)
{
scanf("%c",&ch);
if(ch == 'm') mc.addEdge(s, i*m+j, 1, 0);
else if(ch == 'H') mc.addEdge(i*m+j, t, 1, 0);
//
if(i != 0) mc.addEdge(i*m+j, (i-1)*m+j, INF, 1);
if(i != n-1) mc.addEdge(i*m+j, (i+1)*m+j, INF, 1);
if(j != 1) mc.addEdge(i*m+j, i*m + j - 1, INF, 1);
if(j != m) mc.addEdge(i*m+j, i*m + j + 1, INF, 1);
}
getchar();
}
cout<<mc.getMinCost()<<endl;
}
return 0;
}