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;
}
#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;
}