Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 22062 | Accepted: 11144 |
Description
Your task is to compute the minimum amount of money you need to pay in order to send these n little men into those n different houses. The input is a map of the scenario, a '.' means an empty space, an 'H' represents a house on that point, and am 'm' indicates there is a little man on that point.
You can think of each point on the grid map as a quite large square, so it can hold n little men at the same time; also, it is okay if a little man steps on a grid with a house without entering that house.
Input
Output
Sample Input
2 2 .m H. 5 5 HH..m ..... ..... ..... mm..H 7 8 ...H.... ...H.... ...H.... mmmHmmmm ...H.... ...H.... ...H.... 0 0
Sample Output
2 10 28
題目大意:圖中有n個man和n個home,並且一個人只能住在一個房子裏面,房子和人的個數是相等的。並且每個人移動一步的代價是1,怎麼使
所有人住在房子裏,並且使所有人的代價和最小。
給出一個n×m的圖,m表示人,H表示房子,.表示空地,當然房子不算障礙物,可以穿過
解題思路:這是一個費用流的應用,構圖如下:
建一個源點指向所有人,容量爲1,代價爲0
使每個人指向所有的房子,容量爲1,代價爲人與房子的曼哈頓距離
建一個匯點使所有房子指向它,容量爲1,代價爲0
然後從源點到匯點求費用流即可。
題目要注意的是,在n×m的這張圖上說人的總數不超過100,那麼圖中節點總數爲人+房子+源點+匯點=202
這個題不知道怎麼回事,我做的老是不對,真是奇了怪了,數據沒錯啊!
有誰給我看看一下的代碼怎麼錯了嗎?不勝感激
代碼(我的錯誤的)
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = INT_MAX;
struct node
{
int from, to, cap, flow;
int cost, next;
}E[100002];
int sum, top;
int head[1100], pre[1100];
int dist[1100];
bool vis[1100];
char ch[10100];
void inti()
{
top = 0;
memset ( head, -1, sizeof(head) );
}
void AddEdge(int u, int v, int w, int c)
{
node temp = {u, v, w, 0, c, head[u]};
E[top] = temp;
head[u] = top++;
node temp1 = {v, u, 0, 0, -c, head[v]};
E[top] = temp1;
head[v] = top++;
}
int juli(int x, int y, int m)
{
return abs(y/m-x/m)+abs(y%m-x%m);
}
bool SPFA()
{
int i;
queue<int> q;
for ( i = 0;i <= sum+6; i++ )
dist[i] = inf;
memset ( vis, 0, sizeof(vis) );
memset( pre, -1, sizeof(pre) );
dist[0] = 0;
vis[0] = true;
q.push(0);
while ( !q.empty() )
{
int u = q.front();
q.pop();
vis[u] = false;
for ( i = head[u];i != -1; i = E[i].next )
{
node temp = E[i];
if ( dist[temp.to] > dist[u]+temp.cost&&temp.cap > temp.flow )
{
dist[temp.to] = dist[u]+temp.cost;
pre[temp.to] = i;
if ( !vis[temp.to] )
{
vis[temp.to] = true;
q.push(temp.to);
}
}
}
}
return dist[sum] != inf;
}
int main()
{
int n, m, i, j;
while ( ~scanf ( "%d %d%*c", &n, &m )&&(n || m) )
{
inti();
int hm[1001], mm[1001];
int sum1 = 0, sum2 = 0;
for ( i = 0;i < n; i++ )
{
scanf ( "%s", ch );
for ( j = 0;j < m; j++ )
{
if ( ch[j] == 'm' )
mm[++sum1] = i*m+j;
else if ( ch[j] == 'H' )
hm[++sum2] = i*m+j;
}
getchar();
}
sum = sum1+sum2;
for ( i = 1;i <= sum1; i++ )
AddEdge(0, i, 1, 0);
for ( i = 1;i <= sum2; i++ )
AddEdge(i+sum1, sum, 1, 0);
for ( i = 1;i <= sum1; i++ )
{
for ( j = 1;j <= sum2; j++ )
{
int ju = juli(mm[i], hm[j], m);
AddEdge(i, j+sum1, 1, ju);
}
}
int cost = 0;
while ( SPFA() )
{
int Min = inf;
for( i = pre[sum]; i != -1; i = pre[E[i^1].to])
{
node temp = E[i];
Min = min(Min, temp.cap-temp.flow);
}
for( i = pre[sum]; i != -1; i = pre[E[i^1].to])
{
E[i].flow = E[i].flow+Min;
E[i^1].flow = E[i^1].flow-Min;
cost = cost+E[i].cost;
}
}
printf ( "%d\n", cost );
}
return 0;
}
代碼(正確的)
Memory: 5532K Time: 125MS
Language: C++ Result: Accepted
Source Code
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
const int inf = INT_MAX;
struct node
{
int u, v;
int next;
}E[1000002];
int num, nos, pre[1005];
int head[1005], cost[1005][1005];
void AddEdge(int l, int r, int v)
{
E[num].u = r;
E[num].v = v;
E[num].next = head[l];
head[l] = num++;
}
int juli(int x, int y, int m)
{
return abs(y/m-x/m)+abs(y%m-x%m);
}
int bfs()
{
int visit[1001];
int dist[1001];
int i;
for ( i = 0;i <= nos; i++ )
dist[i] = inf;
memset ( visit, 0, sizeof(visit) );
memset( pre, -1, sizeof(pre) );
queue<int> q;
q.push(0);
visit[0] = 1;
dist[0] = 0;
while ( !q.empty() )
{
int e = q.front();
q.pop();
visit[e] = 0;
for ( i = head[e];i != -1; i = E[i].next )
{
int r = E[i].u;
if ( dist[e]+E[i].v < dist[r] && cost[e][r] )
{
pre[r] = e;
dist[r] = dist[e]+E[i].v;
if ( !visit[r] )
{
q.push(r);
visit[r] = 1;
}
}
}
}
if ( dist[nos] != inf )
return 1;
return 0;
}
void change()
{
int minx = inf;
int i;
for ( i = nos;pre[i] != -1; i = pre[i] )
minx = min(minx, cost[pre[i]][i]);
for ( i = nos;pre[i] != -1; i = pre[i] )
{
cost[pre[i]][i] -= minx;
cost[i][pre[i]] += minx;
}
}
int main()
{
int n, m, i, j;
char str[100001];
while ( scanf("%d %d",&n,&m)&&(n||m) )
{
memset ( head, -1, sizeof(head) );
memset ( cost, 0, sizeof(cost) );
int hm, mm;
hm = mm = 0;
int ms[100001];
int hs[100001];
for ( i = 0;i < n; i++ )
{
scanf ( "%s", str );
for ( j = 0;j < m; j++ )
{
if ( str[j] == 'm' )
ms[++mm] = i*m+j;
else if ( str[j] == 'H' )
hs[++hm] = i*m+j;
}
}
nos = hm+mm+1;
for ( i = 1;i <= mm; i++ )
{
AddEdge(0, i, 0);
AddEdge(i, 0, 0);
cost[0][i] = 1;
cost[i][0] = 0;
}
for ( j = 1;j <= hm; j++ )
{
AddEdge(j+mm, mm+hm+1, 0);
AddEdge(mm+hm+1, j+mm, 0);
cost[j+mm][mm+hm+1] = 1;
cost[mm+hm+1][j+mm] = 0;
}
for ( i = 1;i <= mm; i++ )
{
for ( j = 1;j <= hm; j++ )
{
int ju = juli(ms[i], hs[j], m);
AddEdge(i, j+mm, ju);
AddEdge(j+mm, i, -ju);
cost[i][j+mm] = inf;
cost[j+mm][i] = 0;
}
}
while ( bfs() )
change();
int sum = 0;
for ( i = 1;i <= mm; i++ )
{
for ( j = 1;j <= hm; j++ )
{
sum += (inf-cost[i][j+mm])*juli(ms[i], hs[j], m);
}
}
printf ( "%d\n", sum );
}
return 0;
}
代碼菜鳥,如有錯誤,請多包涵!!!
如有幫助記得支持我一下,謝謝!!!