UVa 1658 - Admiral(最小费用最大流 + 拆点)
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4533
题意:
给出一个v(3≤v≤1000)个点e(3≤e≤10000)条边的有向加权图,
求1~v的两条不相交(除了起点和终点外没有公共点)的路径,使得权和最小。
分析:
把2到v-1的每个结点i拆成i和i'两个结点,中间连一条容量为1,费用为0的边,然后求1到v的流量为2的最小费用流即可。
本题的拆点法是解决结点容量的通用方法。
代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std; /// 结点下标从0开始,注意maxn
struct MCMF {
static const int maxn = * + ;
static const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow, cost;
}; int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn]; // 是否在队列中
int d[maxn]; // Bellman-Ford
int p[maxn]; // 上一条弧
int a[maxn]; // 可改进量 void init(int n) {
this->n = n;
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, int cost) {
edges.push_back((Edge){from, to, cap, , cost});
edges.push_back((Edge){to, from, , , -cost});
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
}
bool BellmanFord(int s, int t, int flow_limit, int& flow, int& cost) {
for(int i = ; i < n; i++) d[i] = INF;
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ; p[s] = ; a[s] = INF;
queue<int> Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = ;
for(int i = ; i < G[u].size(); i++) {
Edge& e = edges[G[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]) {
Q.push(e.to);
inq[e.to] = ;
}
}
}
}
if(d[t] == INF) return false;
if(flow + a[t] > flow_limit) a[t] = flow_limit - flow;
flow += a[t];
cost += d[t] * a[t];
for(int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
}
return true;
}
// 需要保证初始网络中没有负权圈
int MincostMaxflow(int s, int t, int flow_limit) {
int flow = , cost = ;
//while(BellmanFord(s, t, flow, cost));
while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost));
return cost;
}
}; MCMF mc; int main() {
int v, e;
while(~scanf("%d%d", &v, &e)) {
mc.init(v*-);
for(int i = ; i < v-; i++) mc.AddEdge(i, i+v-, , );
for(int a, b, c, i = ; i < e; i++) {
scanf("%d%d%d", &a, &b, &c);
a = (a == || a == v) ? a- : a+v-;
b--;
mc.AddEdge(a, b, , c);
}
printf("%d\n", mc.MincostMaxflow(, v-, ));
}
return ;
}
最小费用最大流模板:
/// 结点下标从0开始,注意maxn
struct MCMF {
static const int maxn = 1e3 + ;
static const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow, cost;
}; int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn]; // 是否在队列中
int d[maxn]; // Bellman-Ford
int p[maxn]; // 上一条弧
int a[maxn]; // 可改进量 void init(int n) {
this->n = n;
for(int i = ; i < n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, int cost) {
edges.push_back((Edge){from, to, cap, , cost});
edges.push_back((Edge){to, from, , , -cost});
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
}
bool BellmanFord(int s, int t, int& flow, int& cost) {
for(int i = ; i < n; i++) d[i] = INF;
memset(inq, , sizeof(inq));
d[s] = ; inq[s] = ; p[s] = ; a[s] = INF;
queue<int> Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = ;
for(int i = ; i < G[u].size(); i++) {
Edge& e = edges[G[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]) {
Q.push(e.to);
inq[e.to] = ;
}
}
}
}
if(d[t] == INF) return false;
//if(flow + a[t] > flow_limit) a[t] = flow_limit - flow;
flow += a[t];
cost += d[t] * a[t];
for(int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
}
return true;
}
// 需要保证初始网络中没有负权圈
int MincostMaxflow(int s, int t) {
int flow = , cost = ;
while(BellmanFord(s, t, flow, cost));
//while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost));
return cost;
}
};
UVa 1658 - Admiral(最小费用最大流 + 拆点)的更多相关文章
- UVa 1658 Admiral(最小费用最大流)
拆点费用流 --------------------------------------------------------------------- #include<cstdio> # ...
- BZOJ-1070 修车 最小费用最大流+拆点+略坑建图
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MB Submit: 3624 Solved: 1452 [Submit][Status] ...
- BZOJ-1877 晨跑 最小费用最大流+拆点
其实我是不想做这种水题的QWQ,没办法,剧情需要 1877: [SDOI2009]晨跑 Time Limit: 4 Sec Memory Limit: 64 MB Submit: 1704 Solve ...
- BZOJ-2324 营救皮卡丘 最小费用可行流+拆下界+Floyd预处理
准备一周多的期末,各种爆炸,回来后状态下滑巨快...调了一晚上+80%下午 2324: [ZJOI2011]营救皮卡丘 Time Limit: 10 Sec Memory Limit: 256 MB ...
- BZOJ-1927 星际竞速 最小费用最大流+拆点+不坑建图
1927: [Sdoi2010]星际竞速 Time Limit: 20 Sec Memory Limit: 259 MB Submit: 1593 Solved: 967 [Submit][Statu ...
- hdu 4494 Teamwork 最小费用最大流
Teamwork Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4494 ...
- bzoj 1877 [SDOI2009]晨跑(最小费用最大流)
Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十 ...
- UVA 1658 海军上将(拆点法+最小费用限制流)
海军上将 紫书P375 这题我觉得有2个难点: 一是拆点,要有足够的想法才能把这题用网络流建模,并且知道如何拆点. 二是最小费用限制流,最小费用最大流我们都会,但如果限制流必须为一个值呢?比如这题限制 ...
- UVA - 1658 Admiral (最小费用最大流)
最短路对应费用,路径数量对应流量.为限制点经过次数,拆点为边.跑一次流量为2的最小费用最大流. 最小费用最大流和最大流EK算法是十分相似的,只是把找增广路的部分换成了求费用的最短路. #include ...
随机推荐
- Maven 配置Tomcat
1.Tomcat conf 下的tomcat-users.xml 增加 <role rolename="manager"/> <role rolename=&qu ...
- 企业为什么需要实施BPM?
背景:众所周知,近几年企业信息化发展迅速,业务管理系统从大到小,数量众多,如ERP,SCM,PLM,CRM,EHR,OA,BI…… 等,企业的管理人员进行管理的主要手段是通过各个业务系统获得各种管理报 ...
- C# XML相关
XmlDocument doc = new XmlDocument(); 1.string类型的xml,如何转换成xml类型 doc.LoadXml("需要传入的string类型的xml&q ...
- 十一、cent OS下搭建SVN服务器
安装SVN命令:yum install subversion 查看安装位置:rpm -ql subversion,我们看到它在/usr/bin目录下生成了svn的二进制文件 查看svn版本:/usr/ ...
- ps命令详解加例子
Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信 ...
- 初学zookeeper--自定义事件监听
zk有四种节点类型: 持久节点,持久顺序节点,临时节点,临时顺序节点. 自定义监听事件时,在节点的创建,修改,删除的方法第一行都需要加入是否监听的一个方法: //开启监听的方法.第二个参数表示是否开启 ...
- JS之捕获冒泡和事件委托
一.事件流(捕获,冒泡) 事件流:指从页面中接收事件的顺序,有冒泡流和捕获流. 当页面中发生某种事件(比如鼠标点击,鼠标滑过等)时,毫无疑问子元素和父元素都会接收到该事件,可具体顺序是怎样的呢?冒 ...
- Js的核心:找到DOM
掌握 JavaScript 的核心之一:DOM,能够熟悉DOM相关操作,了解JavaScript事件机制 一.使用getElementById().getElementsByTagName().chi ...
- html 之 position用法
引用: position的四个属性值: 1.relative2.absolute3.fixed4.static下面分别讲述这四个属性. <div id="parent"> ...
- js修改日期
需求说明: (1)首先是input显示年月日时分格式时间,其中年月日实在本地时间基础上,加上后面联动值.小时默认08:00不变 (2)后面input内显示天数,右侧加减按钮,控制天数,天数确定后,前面 ...