poj2195

题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少。

分析:最小费用最大流每个人一个点,每个房子一个点,每个人到所有房子加容量为1费用为二者距离的边,源到所有人加容量为1费用为0的边,所有房子到汇加容量为1费用为0的边。因为没有初始化ne,wa了两次。渐渐开始理解网络流的题型了,是一种可以自由分配,求最优分配方案的题。

View Code
#include <iostream>
#include
<cstdlib>
#include
<cstring>
#include
<cstdio>
#include
<cmath>
usingnamespace std;

#define inf 0x3f3f3f3f
#define N 205
#define E 40000

struct XPoint
{
int x, y;
}house[N], man[N];

int n, m;
int hcount, mcount;

struct network
{
int nv, ne, pnt[E], nxt[E];
int vis[N], que[N], head[N], pv[N], pe[N];
int flow, cap[E];
int cost, dis[E], d[N];
int src, sink;
void addedge(int u, int v, int c, int w)
{
pnt[ne]
= v;
cap[ne]
= c;
dis[ne]
=+w;
nxt[ne]
= head[u];
head[u]
= (ne++);
pnt[ne]
= u;
cap[ne]
=0;
dis[ne]
=-w;
nxt[ne]
= head[v];
head[v]
= (ne++);
}
int mincost()
{
int i, k, f, r;
int mxf;
for (flow =0, cost =0;;)
{
memset(pv,
-1, sizeof(pv));
memset(vis,
0, sizeof(vis));
for (i =0; i < nv; ++i)
d[i]
= inf;
d[src]
=0;
pv[src]
= src;
vis[src]
=1;

for (f =0, r =1, que[0] = src; r != f;)
{
i
= que[f++];
vis[i]
=0;
if (N == f)
f
=0;
for (k = head[i]; k !=-1; k = nxt[k])
if (cap[k] && dis[k] + d[i] < d[pnt[k]])
{
d[pnt[k]]
= dis[k] + d[i];
if (0== vis[pnt[k]])
{
vis[pnt[k]]
=1;
que[r
++] = pnt[k];
if (N == r)
r
=0;
}
pv[pnt[k]]
= i;
pe[pnt[k]]
= k;
}
}
if (-1== pv[sink])
break;
for (k = sink, mxf = inf; k != src; k = pv[k])
if (cap[pe[k]] < mxf)
mxf
= cap[pe[k]];
flow
+= mxf;
cost
+= d[sink] * mxf;
for (k = sink; k != src; k = pv[k])
{
cap[pe[k]]
-= mxf;
cap[pe[k]
^1] += mxf;
}
}
return cost;
}
void build()
{
hcount
= mcount =0;
for (int i =0; i < n; i++)
{
for (int j =0; j < m; j++)
{
char ch = getchar();
if (ch =='H')
{
house[hcount].x
= i;
house[hcount].y
= j;
hcount
++;
}
if (ch =='m')
{
man[mcount].x
= i;
man[mcount].y
= j;
mcount
++;
}
}
getchar();
}
nv
= hcount *2+2;
ne
=0;
memset(head,
-1, sizeof(head));
for (int i =0; i < mcount; i++)
for (int j =0; j < hcount; j++)
addedge(i, j
+ mcount, 1, abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y));
src
= nv -2;
sink
= nv -1;
for (int i =0; i < mcount; i++)
addedge(src, i,
1, 0);
for (int i =0; i < hcount; i++)
addedge(i
+ mcount, sink, 1, 0);
}
}g;

int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%d%d", &n, &m), n | m)
{
getchar();
g.build();
int ans = g.mincost();
printf(
"%d\n", ans);
}
return0;
}
posted @ 2011-06-05 17:30  金海峰  阅读(719)  评论(0编辑  收藏  举报