poj_2195 最小费用最大流
题目大意
一个nxm的地图,地图上的横纵交错成nxm个交叉点,其中有k个交叉点为房间,k个交叉点为k个小人的初始位置。小人可以在地图上沿着水平或垂直方向行走,每走一步的代价为1。求这k个小人分别到达k个不同的房间,所花费的总代价的最小值。
题目分析
k个小人走到k个房间节点,走出k条不同的路径,形成一个网络,求出花费最少的k条路径。每个房间只能容纳一个小人,视为小人节点到房间节点的路径上的容量为1,这样就不会出现多个小人挤到同一个房间。那么可以将问题转化为网络流: 
    添加源点s和汇点t,从s出发引出k条边分别到达k个小人,边的容量为1,费用为0;从k个房间节点分别引出一条边到达t,边的容量为1,费用为0;从k个小人节点分别引出k条边达到k个房间节点,边的容量为1,单位费用为小人到房间的最短距离。这样就构造出了一个网络流图,然后求解从源点s到达汇点t的最小费用最大流。
ps:这种有限制条件(比如容量有限制)的问题可以考虑转化为网络流。
实现(c++)
#include<stdio.h>
#include<string.h>
#include<queue>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 1 << 25
#define MAX_NODE 220
#define MAX_EDGE_NUM 40005
#define min(a, b) a<b?a:b
struct Edge{
int to;
int vol;
int cost;
int next;
};
Edge gEdges[MAX_EDGE_NUM];
int gPre[MAX_NODE];
int gPath[MAX_NODE];
int gDist[MAX_NODE];
int gHead[MAX_NODE];
int gEdgeCount;
void InsertEdge(int u, int v, int vol, int cost){
gEdges[gEdgeCount].to = v;
gEdges[gEdgeCount].vol = vol;
gEdges[gEdgeCount].cost = cost;
gEdges[gEdgeCount].next = gHead[u];
gHead[u] = gEdgeCount++; gEdges[gEdgeCount].to = u;
gEdges[gEdgeCount].vol = 0;
gEdges[gEdgeCount].cost = -cost;
gEdges[gEdgeCount].next = gHead[v];
gHead[v] = gEdgeCount++;
}
//spfa算法求最短路(即增广单位费用最小的从源到汇的路径)
bool Spfa(int s, int t){
memset(gDist, 0x7F, sizeof(gDist));
memset(gPre, -1, sizeof(gPre));
gDist[s] = 0;
queue<int>Q;
Q.push(s);
while (!Q.empty()){
int u = Q.front();
Q.pop();
for (int e = gHead[u]; e != -1; e = gEdges[e].next){
int v = gEdges[e].to;
if (gEdges[e].vol > 0 && gDist[v] > gDist[u] + gEdges[e].cost){
gDist[v] = gDist[u] + gEdges[e].cost;
gPre[v] = u;
gPath[v] = e;
Q.push(v);
}
}
}
return gPre[t] != -1;
} int MinCostFlow(int s, int t){
int cost = 0;
int max_flow = 0;
int u, v, e;
while (Spfa(s, t)){
int f = INF;
for (u = t; u != s; u = gPre[u]){
f = min(f, gEdges[gPath[u]].vol);
} for (u = t; u != s; u = gPre[u]){
e = gPath[u];
gEdges[e].vol -= f;
gEdges[e^1].vol += f; //反向边
}
max_flow += f;
cost += f*gDist[t];
}
return cost;
} char gMap[105][105];
vector<pair<int, int> > gHousVec;
vector<pair<int, int> > gManVec;
//建图
void BuildGraph(){
int n = gHousVec.size();
// 源点0,连接到每个小人结点,流量为1,单位费用为0
for (int u = 1; u <= n; u++){
InsertEdge(0, u, 1, 0);
}
for (int i = 0; i < n; i++){
for (int j = 0; j < n; j++){
//求出小人i到房间j的最短距离
int min_dist = abs(gManVec[i].first - gHousVec[j].first) + abs(gManVec[i].second - gHousVec[j].second);
//建边,连接小人i和房间j
InsertEdge(i + 1, j + n + 1, 1, min_dist);
}
}
//汇点 2*n+1,连接各个房间借点到汇点,流量为1,单位费用为0
for (int u = 1; u <= n; u++){
InsertEdge(n + u, 2 * n + 1, 1, 0);
}
}
int main(){
int n, m;
while (scanf("%d %d", &n, &m) && n && m){
char tmp;
gHousVec.clear(); //初始化
gManVec.clear();
memset(gHead, -1, sizeof(gHead)); //图的初始化
gEdgeCount = 0; //图的初始化 for (int i = 1; i <= n; i++){
getchar();
for (int j = 1; j <= m; j++){
scanf("%c", &tmp);
if (tmp == 'H'){
gHousVec.push_back(pair<int, int>(i, j));
}
else if (tmp == 'm'){
gManVec.push_back(pair<int, int>(i, j));
}
}
}
BuildGraph(); //建图
int cost = MinCostFlow(0, 2 * gHousVec.size() + 1); //求解最小费用最大流
printf("%d\n", cost);
}
return 0;
}
poj_2195 最小费用最大流的更多相关文章
- [板子]最小费用最大流(Dijkstra增广)
		
最小费用最大流板子,没有压行.利用重标号让边权非负,用Dijkstra进行增广,在理论和实际上都比SPFA增广快得多.教程略去.转载请随意. #include <cstdio> #incl ...
 - bzoj1927最小费用最大流
		
其实本来打算做最小费用最大流的题目前先来点模板题的,,,结果看到这道题二话不说(之前打太多了)敲了一个dinic,快写完了发现不对 我当时就这表情→ =_=你TM逗我 刚要删突然感觉dinic的模 ...
 - ACM/ICPC 之 卡卡的矩阵旅行-最小费用最大流(可做模板)(POJ3422)
		
将每个点拆分成原点A与伪点B,A->B有两条单向路(邻接表实现时需要建立一条反向的空边,并保证环路费用和为0),一条残留容量为1,费用为本身的负值(便于计算最短路),另一条残留容量+∞,费用为0 ...
 - HDU5900 QSC and Master(区间DP + 最小费用最大流)
		
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5900 Description Every school has some legends, ...
 - P3381 【模板】最小费用最大流
		
P3381 [模板]最小费用最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行 ...
 - 【BZOJ-3876】支线剧情         有上下界的网络流(有下界有源有汇最小费用最大流)
		
3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 821 Solved: 502[Submit][Status ...
 - hdu 4411 2012杭州赛区网络赛 最小费用最大流 ***
		
题意: 有 n+1 个城市编号 0..n,有 m 条无向边,在 0 城市有个警察总部,最多可以派出 k 个逮捕队伍,在1..n 每个城市有一个犯罪团伙, 每个逮捕队伍在每个城市可以选 ...
 - UVa11082 Matrix Decompressing(最小费用最大流)
		
题目大概有一个n*m的矩阵,已知各行所有数的和的前缀和和各列所有数的和的前缀和,且矩阵各个数都在1到20的范围内,求该矩阵的一个可能的情况. POJ2396的弱化版本吧..建图的关键在于: 把行.列看 ...
 - UVa12092 Paint the Roads(最小费用最大流)
		
题目大概说一个n个点m条带权有向边的图,要给边染色,染色的边形成若干个回路且每个点都恰好属于其中k个回路.问最少要染多少边权和的路. 一个回路里面各个点的入度=出度=1,那么可以猜想知道各个点如果都恰 ...
 
随机推荐
- 【Unity笔记】获得鼠标点击屏幕的位置,并转成世界坐标
			
Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
 - 阿里云ECS,WampServer无法访问外网
			
情况: 使用阿里云ECS服务器.服务端打开WampServer后,在服务端能通过127.0.0.1和localhost访问到WampServer的首页. 阿里云已经给了外网IP,不需要路由器再做端口映 ...
 - c++的内存分配
			
C++堆和栈的分配 腾讯.金山笔试常考 栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈. 堆区(heap) — 一般由程序员分配释放, ...
 - Redis Key 过期策略
			
redis 官方提供的 conf https://raw.github.com/antirez/redis/2.2/redis.conf 中6中过期策略的具体方式.redis 中的默认的过期策略是vo ...
 - poj3208 Apocalypse Someday 数位dp+二分 求第K(K <= 5*107)个有连续3个6的数。
			
/** 题目:poj3208 Apocalypse Someday 链接:http://poj.org/problem?id=3208 题意:求第K(K <= 5*107)个有连续3个6的数. ...
 - 网络配置br0   brtcl
			
1.brctl addbr br0 如果根据第3步,那这里不用写 2.brctl addif br0 eth0 如果第3步写了,这里也不用 这时候用ssh应该会断网... 3.设置 ...
 - mysql  从sql存储文件恢复数据库乱码
			
场景一: 一台电脑上导出的sql文件到另一台电脑上恢复数据库,汉字全部是乱码,然后可能还有部分数据提示超长. 场景二: 拿到的sql文件不是原始的导出sql文件,只有表结构和表数据,出现的问题和场景一 ...
 - MVC下载远程文件流(WebClient)
			
public ActionResult DownLoad_File() { return File(ScLiu(PathUrl), "application/octet-stream&quo ...
 - 【Java面试题】58  char型变量中能不能存贮一个中文汉字?为什么?
			
char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦.不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么 ...
 - OpenGL模板缓冲区与模板测试
			
原文地址:http://www.blogjava.net/qileilove/archive/2014/01/23/409269.html 帧缓冲区有许多缓冲区构成,这些缓冲区大致分为: 颜色缓冲区: ...