博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
D - Going Home POJ - 2195 网络流
阅读量:4678 次
发布时间:2019-06-09

本文共 4446 字,大约阅读时间需要 14 分钟。

On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent point. For each little man, you need to pay a $1 travel fee for every step he moves, until he enters a house. The task is complicated with the restriction that each house can accommodate only one little man. 
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

There are one or more test cases in the input. Each case starts with a line giving two integers N and M, where N is the number of rows of the map, and M is the number of columns. The rest of the input will be N lines describing the map. You may assume both N and M are between 2 and 100, inclusive. There will be the same number of 'H's and 'm's on the map; and there will be at most 100 houses. Input will terminate with 0 0 for N and M.

Output

For each test case, output one line with the single integer, which is the minimum amount, in dollars, you need to pay.

Sample Input

2 2.mH.5 5HH..m...............mm..H7 8...H.......H.......H....mmmHmmmm...H.......H.......H....0 0

Sample Output

21028 这个题目难在建图,就是把每一个人的位置,和每一个房子连起来,容量为1,费用为两个之间的距离。 然后就跑一个最小费用最大流就可以了。
#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3fusing namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int maxn = 1000 + 10;struct edge{ int u, v, c, f, cost; edge(int u, int v, int c, int f, int cost) :u(u), v(v), c(c), f(f), cost(cost) {}};vector
e;vector
G[maxn];int a[maxn];//找增广路每个点的水流量int p[maxn];//每次找增广路反向记录路径int d[maxn];//SPFA算法的最短路int inq[maxn];//SPFA算法是否在队列中int s, t;void init(){ for (int i = 0; i <= maxn; i++)G[i].clear(); e.clear();}void add(int u, int v, int c, int cost){ e.push_back(edge(u, v, c, 0, cost)); e.push_back(edge(v, u, 0, 0, -cost)); int m = e.size(); G[u].push_back(m - 2); G[v].push_back(m - 1);}bool bellman(int s, int t, int& flow, long long & cost){ memset(d, inf, sizeof(d)); memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = 1;//源点s的距离设为0,标记入队 p[s] = 0; a[s] = INF;//源点流量为INF(和之前的最大流算法是一样的) queue
q;//Bellman算法和增广路算法同步进行,沿着最短路拓展增广路,得出的解一定是最小费用最大流 q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); inq[u] = 0;//入队列标记删除 for (int i = 0; i < G[u].size(); i++) { edge & now = e[G[u][i]]; int v = now.v; if (now.c > now.f && d[v] > d[u] + now.cost) //now.c > now.f表示这条路还未流满(和最大流一样) //d[v] > d[u] + e.cost Bellman 算法中边的松弛 { d[v] = d[u] + now.cost;//Bellman 算法边的松弛 p[v] = G[u][i];//反向记录边的编号 a[v] = min(a[u], now.c - now.f);//到达v点的水量取决于边剩余的容量和u点的水量 if (!inq[v]) { q.push(v); inq[v] = 1; }//Bellman 算法入队 } } } if (d[t] == INF)return false;//找不到增广路 flow += a[t];//最大流的值,此函数引用flow这个值,最后可以直接求出flow cost += (long long)d[t] * (long long)a[t];//距离乘上到达汇点的流量就是费用 for (int u = t; u != s; u = e[p[u]].u)//逆向存边 { e[p[u]].f += a[t];//正向边加上流量 e[p[u] ^ 1].f -= a[t];//反向边减去流量 (和增广路算法一样) } return true;}int MincostMaxflow(int s, int t, long long & cost){ cost = 0; int flow = 0; while (bellman(s, t, flow, cost));//由于Bellman函数用的是引用,所以只要一直调用就可以求出flow和cost return flow;//返回最大流,cost引用可以直接返回最小费用}struct node{ int x, y; node(int x=0,int y=0):x(x),y(y){}};node peo[110], house[110];char mp[110][110];int main(){ int n, m; while(cin>>n>>m) { init(); int cas = 0, tot = 0; if (n == 0 && m == 0) break; for (int i = 1; i <= n; i++) { cin >> mp[i] + 1; for(int j=1;j<=m;j++) { if (mp[i][j] == 'm') peo[++cas] = node(i, j); if (mp[i][j] == 'H') house[++tot] = node(i, j); } } s = 0, t = cas + tot + 1; for (int i = 1; i <= cas; i++) add(s, i, 1, 0); for (int i = 1; i <= tot; i++) add(cas + i, t, 1, 0); for(int i=1;i<=cas;i++) { for(int j=1;j<=tot;j++) { int cost = abs(peo[i].x - house[j].x) + abs(peo[i].y - house[j].y); add(i, j + cas, 1, cost); } } ll cost = 0; int ans = MincostMaxflow(s, t, cost); printf("%lld\n", cost); } return 0;}

 

 

转载于:https://www.cnblogs.com/EchoZQN/p/10797938.html

你可能感兴趣的文章
xftp Initialize Flexnet Service failed / Error code: 50003
查看>>
【软件技巧】Sublime Text为不同语法定义不同高亮
查看>>
iframe的滚动栏问题:显示/隐藏滚动栏
查看>>
reactor模式:单线程的reactor模式
查看>>
Pair_Work Project
查看>>
good
查看>>
JavaScript之isNaN()函数讲解
查看>>
如何培养自己的管理才能?
查看>>
从App Store上获取已经上架的App版本信息
查看>>
SpringMvc实现日期转换
查看>>
Android稳定性测试之Log分析
查看>>
WPF中使用ObjectDataProvider绑定方法
查看>>
万能数据库查询分析器中文版本《DB查询分析器》几年来在“中关村在线”首次大榜小榜都能够榜上有名...
查看>>
孔明灯-噪点插画
查看>>
类与接口(三)java中的接口与嵌套接口
查看>>
VS关闭Browser Link
查看>>
【题解】山头狙击战
查看>>
USB小白学习之路(3) 通过自定义请求存取外部RAM
查看>>
Solr:通过solr admin对索引库维护<四>
查看>>
mysql写注释的几种方法
查看>>