http://poj.org/problem?id=2195

题意:有一个地图里面有N个人和N个家,每走一格的花费是1,问让这N个人分别到这N个家的最小花费是多少。

思路:通过这个题目学了最小费用最大流。最小费用最大流是保证在流量最大的情况下,使得费用最小。

建图是把S->人->家->T这些边弄上形成一个网络,边的容量是1(因为一个人只能和一个家匹配),边的费用是曼哈顿距离,反向边的费用是-cost。

算法的思想大概是通过SPFA找增广路径,并且找的时候费用是可以松弛的。当找到这样一条增广路就进行更新。注意这里的费用是单位流量的费用。反向边权为-cost是因为悔棋的时候费用要增加cost。

 #include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
#define N 205
#define INF 0x3f3f3f3f
struct node {
int x, y;
node () {}
node (int x, int y) : x(x), y(y) {}
};
struct Edge {
int cap, u, v, cost;
Edge() {}
Edge(int u, int v, int cap, int cost) : u(u), v(v), cap(cap), cost(cost) {}
}edge[N*N];
vector<node> p, h;
vector<int> G[N];
int tot, dis[N], inq[N], pre[N], S, T; void AddEdge(int u, int v, int cap, int cost) {
edge[tot] = Edge(u, v, cap, cost);
G[u].push_back(tot++);
edge[tot] = Edge(v, u, , -cost); // 表示反向增广(悔棋)的时候费用增加cost
G[v].push_back(tot++);
} int CalDis(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
} bool SPFA() {
memset(inq, , sizeof(inq));
memset(dis, INF, sizeof(dis));
queue<int> que; que.push(S);
dis[S] = ; inq[S] = ;
while(!que.empty()) {
int u = que.front(); que.pop(); inq[u] = ;
for(int i = ; i < G[u].size(); i++) {
Edge &e = edge[G[u][i]];
if(e.cap > && dis[e.v] > e.cost + dis[u]) {
// 当可以增广并且费用可以松弛的时候
dis[e.v] = e.cost + dis[u];
pre[e.v] = G[u][i]; // 记录路径
if(inq[e.v]) continue;
que.push(e.v); inq[e.v] = ;
}
}
}
return dis[T] < INF; // 返回是否有增广路径
} void MFMC(int &mincost, int &maxflow) {
int ans = , flow = INF, p;
// 从汇点沿着此次增广的路径往回走,当找到源点的时候退出
for(int u = T; u; u = edge[p].u) {
p = pre[u]; // 找增广的流量
if(edge[p].cap < flow) flow = edge[p].cap;
}
for(int u = T; u; u = edge[p].u) {
p = pre[u];
edge[p].cap -= flow; // 更新每条边的流量
edge[p^].cap += flow;
ans += flow * edge[p].cost; // 费用 = 单位费用 * 流量
}
mincost += ans, maxflow += flow;
} int main() {
int n, m;
char s[];
while(scanf("%d%d", &n, &m), n + m) {
p.clear(); h.clear();
for(int i = ; i < n; i++) {
scanf("%s", s);
for(int j = ; j < m; j++) {
if(s[j] == 'H') h.push_back(node(i, j));
if(s[j] == 'm') p.push_back(node(i, j));
}
}
tot = ; int sz1 = p.size(), sz2 = h.size();
S = , T = sz1 + sz2 + ;
for(int i = ; i <= T; i++) G[i].clear();
for(int i = ; i < sz1; i++) // S到man
AddEdge(S, i + , , );
for(int i = ; i < sz2; i++) // house到T
AddEdge(i + + sz1, T, , );
for(int i = ; i < sz1; i++) {
for(int j = ; j < sz2; j++) {
int c = CalDis(p[i].x, p[i].y, h[j].x, h[j].y);
AddEdge(i + , j + + sz1, , c);
}
} int mincost = , maxflow = ;
while(SPFA()) MFMC(mincost, maxflow);
printf("%d\n", mincost);
}
return ;
}

POJ 2195:Going Home(最小费用最大流)的更多相关文章

  1. POJ 2195 - Going Home - [最小费用最大流][MCMF模板]

    题目链接:http://poj.org/problem?id=2195 Time Limit: 1000MS Memory Limit: 65536K Description On a grid ma ...

  2. POJ 2195 Going Home 最小费用最大流 尼玛,心累

    D - Going Home Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Subm ...

  3. poj 2195 Going Home(最小费用最大流)

    题目:http://poj.org/problem?id=2195 有若干个人和若干个房子在一个给定网格中,每人走一个都要一定花费,每个房子只能容纳一人,现要求让所有人进入房子,且总花费最小. 构造一 ...

  4. poj 2351 Farm Tour (最小费用最大流)

    Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17230   Accepted: 6647 Descri ...

  5. POJ 2157 Evacuation Plan [最小费用最大流][消圈算法]

    ---恢复内容开始--- 题意略. 这题在poj直接求最小费用会超时,但是题意也没说要求最优解. 根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的 ...

  6. poj 2135 Farm Tour 最小费用最大流建图跑最短路

    题目链接 题意:无向图有N(N <= 1000)个节点,M(M <= 10000)条边:从节点1走到节点N再从N走回来,图中不能走同一条边,且图中可能出现重边,问最短距离之和为多少? 思路 ...

  7. POJ 3680: Intervals【最小费用最大流】

    题目大意:你有N个开区间,每个区间有个重量wi,你要选择一些区间,使得满足:每个点被不超过K个区间覆盖的前提下,重量最大 思路:感觉是很好想的费用流,把每个区间首尾相连,费用为该区间的重量的相反数(由 ...

  8. POJ 2135 Farm Tour [最小费用最大流]

    题意: 有n个点和m条边,让你从1出发到n再从n回到1,不要求所有点都要经过,但是每条边只能走一次.边是无向边. 问最短的行走距离多少. 一开始看这题还没搞费用流,后来搞了搞再回来看,想了想建图不是很 ...

  9. [poj] 1235 Farm Tour || 最小费用最大流

    原题 费用流板子题. 费用流与最大流的区别就是把bfs改为spfa,dfs时把按deep搜索改成按最短路搜索即可 #include<cstdio> #include<queue> ...

  10. POJ 2516 Minimum Cost [最小费用最大流]

    题意略: 思路: 这题比较坑的地方是把每种货物单独建图分开算就ok了. #include<stdio.h> #include<queue> #define MAXN 500 # ...

随机推荐

  1. php date()获取的时间不对解决办法

    因为php默认获取的是格林威治时间,与北京时间相差8小时. 我们要获取到北京时间有两个办法: 1.修改php.ini配置文件: 打开php.ini文件,一般在php配置根目录下,找到其中的 ;date ...

  2. js封装

    方法一: function Tetrio(singleW){ if(singleW == undefined){ singleW = 18; } this.x = 0; this.y = 0;} Te ...

  3. MySQL Server-id踩到的坑

    最近踩到一个说大不大,说小不小的坑,在此分享出来给各位同学.事情是这样的,线上有2台服务器,1主1从.A -> B,B服务器从A服务器同步数据.每天使用xtrabackup在B服务器上面进行全备 ...

  4. jdbc中java与mysql数据类型的映射

    注:这种类型匹配不是强制性标准,特定的JDBC厂商可能会改变这种类型匹配.例如Oracle中的DATE类型是包含时分秒,而java.sql.Date仅仅支持年月日.

  5. 关于oracle的笔记

    1.查看一个表暂用的表空间大小: SELECT bytes/1024/1024||'MB',a.*FROM user_segments a WHERE a.segment_name ='TL_SP_N ...

  6. response的outputStream输出数据的问题

    package cn.itcast.response; import java.io.IOException; import java.io.OutputStream; import java.io. ...

  7. Task示例,多线程

    class Program { static void Main(string[] args) { Run(); } public static async void Run() { var task ...

  8. yii2.0 网址重写

  9. maven说

    maven打包命令:mvn assembly:assembly 打包成jar包需要修改配置把unpack改成false文件在: C:\Users\Administrator\.m2\repositor ...

  10. Android studio -VSN 使用笔记

    1.Android studio 安装 中文组官网:http://www.android-studio.org/ 常见问题参考: 分支冲突合并 http://blog.csdn.net/tearsmo ...