博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
luogu4012 深海机器人问题 网络流
阅读量:5046 次
发布时间:2019-06-12

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

关键词:最小费用最大流

题目大意:海底是个网格,每个网格边有一定价值的海底化石。每个路线可经过无限个机器人,但上面的化石只能采一次。机器人可沿网格边向东或向北移动。给定机器人起点和终点位置及所能容纳的机器人数,求能获得的最大价值。

网络流:把一个机器人运动的轨迹看作一个流量为1的流。

化石只能采一次,我们想到建立一条容量为1的边,价值为-化石价值。以后该路线可经过无限个机器人,我们想到建立一条容量为∞的边,价值为0。S连起点,终点连T,容量为其所能容纳的机器人数。

#include 
#include
#include
#include
#include
#include
using namespace std;#define LOOP(i, n) for(int i=1; i<=n; i++)#define ID(col, row) row * (lastCol + 1) + col + 1const int MAX_NODE = 20 * 20, MAX_EDGE = MAX_NODE*MAX_NODE * 4, INF = 0x3f3f3f3f, MAX_ROW = 20, MAX_COL = 20;struct MCMF{ struct Node; struct Edge; struct Node { Edge *Head, *Prev; int Dist, Id; bool Inq; }; struct Edge { int Cap, Cost, OrgCap; Node *From, *To; Edge *Next, *Rev; Edge(int cap, int cost, Node *from, Node *to, Edge *next) :Cap(cap), OrgCap(cap), Cost(cost), From(from), To(to), Next(next) {} }; Node _nodes[MAX_NODE]; Edge *_edges[MAX_EDGE]; int _vCount = 0, _eCount = 0; Node *Start, *Sink; int TotFlow, TotCost; void Init(int n, int sId, int tId) { _vCount = n; _eCount = 0; Start = &_nodes[sId], Sink = &_nodes[tId]; TotFlow = TotCost = 0; } Edge* AddEdge(Node *from, Node *to, int cap, int cost) { Edge *e = _edges[++_eCount] = new Edge(cap, cost, from, to, from->Head); e->From->Head = e; return e; } void Build(int uId, int vId, int cap, int cost) { //printf("%d->%d\n", uId, vId); Node *u = uId + _nodes, *v = vId + _nodes; u->Id = uId; v->Id = vId; Edge *edge1 = AddEdge(u, v, cap, cost), *edge2 = AddEdge(v, u, 0, -cost); edge1->Rev = edge2; edge2->Rev = edge1; } bool SPFA() { queue
q; LOOP(i, _vCount) { _nodes[i].Prev = NULL; _nodes[i].Dist = INF; _nodes[i].Inq = false; } Start->Dist = 0; q.push(Start); while (!q.empty()) { Node *u = q.front(); q.pop(); u->Inq = false; for (Edge *e = u->Head; e; e = e->Next) { if (e->Cap && u->Dist + e->Cost < e->To->Dist) { e->To->Dist = u->Dist + e->Cost; e->To->Prev = e; if (!e->To->Inq) { e->To->Inq = true; q.push(e->To); } } } } return Sink->Prev; } void Proceed() { while (SPFA()) { assert(Sink->Dist != INF); int minFlow = INF; for (Edge *e = Sink->Prev; e; e = e->From->Prev) minFlow = min(minFlow, e->Cap); TotFlow += minFlow; for (Edge *e = Sink->Prev; e; e = e->From->Prev) { e->Cap -= minFlow; e->Rev->Cap += minFlow; TotCost += minFlow * e->Cost; } } }}g;int main(){#ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin);#endif int totStart, totTarget, lastCol, lastRow, row, col, horiVal, vertVal, robotCnt; scanf("%d%d%d%d", &totStart, &totTarget, &lastRow, &lastCol); int sId = ID(lastCol, lastRow) + 1, tId = ID(lastCol, lastRow) + 2; g.Init(tId, sId, tId); for (int row = 0; row <= lastRow; row++) for (int col = 1; col <= lastCol; col++) { scanf("%d", &horiVal); g.Build(ID((col - 1), row), ID(col, row), INF, 0); g.Build(ID((col - 1), row), ID(col, row), 1, -horiVal); } for (int col = 0; col <= lastCol; col++) for (int row = 1; row <= lastRow; row++) { scanf("%d", &vertVal); g.Build(ID(col, (row - 1)), ID(col, row), INF, 0); g.Build(ID(col, (row - 1)), ID(col, row), 1, -vertVal); } LOOP(i, totStart) { scanf("%d%d%d", &robotCnt, &row, &col); g.Build(sId, ID(col, row), robotCnt, 0); } LOOP(i, totTarget) { scanf("%d%d%d", &robotCnt, &row, &col); g.Build(ID(col, row), tId, robotCnt, 0); } g.Proceed(); printf("%d\n", -g.TotCost); return 0;}
View Code

注意:宏替换写函数时,对其所操作的参数尽量打括号,否则会出现运算顺序问题。

 

转载于:https://www.cnblogs.com/headboy2002/p/8453494.html

你可能感兴趣的文章
玩转storm
查看>>
浅谈 @RequestParam 和@PathVariable
查看>>
NSEnumerator用法小结
查看>>
Feign使用Hystrix无效原因及解决方法
查看>>
Sam做题记录
查看>>
C++的引用
查看>>
python itertools
查看>>
http://lorempixel.com/ 可以快速产生假图
查看>>
编写一个函数isMerge,判断一个字符串str是否可以由其他两个字符串part1和part2“组合”而成...
查看>>
文件操作
查看>>
NYOJ-613//HDU-1176-免费馅饼,数字三角形的兄弟~~
查看>>
graphite custom functions
查看>>
ssh无密码登陆屌丝指南
查看>>
一个自己写的判断2个相同对象的属性值差异的工具类
查看>>
oracle连接的三个配置文件(转)
查看>>
Java 8 中如何优雅的处理集合
查看>>
[HNOI2012]永无乡 线段树合并
查看>>
Centos下源码安装git
查看>>
控件发布:div2dropdownlist(div模拟dropdownlist控件)
查看>>
[置顶] 细说Cookies
查看>>