经典网络流题目模板(P3376 + P2756 + P3381 : 最大流 + 二分图匹配 + 最小费用最大流)...

题目来源

  • P3376 【模板】网络最大流
  • P2756 飞行员配对方案问题
  • P3381 【模板】最小费用最大流

最大流

最大流问题是网络流的经典类型之一,用处广泛,个人认为网络流问题最具特点的操作就是建反向边,这样相当于给了反悔的机会,不断地求增广路的,最终得到最大流

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e5 + 10;struct Edge {int to, next, flow;    //flow记录这条边当前的边残量
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}//向图中增加一条容量为exp的边(增广路)
int dfs(int u,int exp)
{if (u == t) return exp;            //到达汇点,当前水量全部注入vis[u] = true;                    //表示已经到了过了for(int i = head[u] ; i != -1  ;i = edge[i].next){int v = edge[i].to;if(!vis[v] && edge[i].flow > 0){int flow = dfs(v, min(exp, edge[i].flow));if(flow > 0)            //形成了增广路
            {edge[i].flow -= flow;edge[i ^ 1].flow += flow;return flow;}}}return 0;                        //无法形成增广路的情况
}//求最大流
int max_flow()
{int flow = 0;while(true){memset(vis, 0, sizeof(vis));int part_flow = dfs(s, inf);if (part_flow == 0) return flow;flow += part_flow;}
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow;i <= m; i++){scanf("%d%d%d", &u, &v, &flow);add(u, v, flow);add(v, u, 0);}printf("%d\n", max_flow());}return 0;
}
最简单算法-Ford-Fulkerson
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) "["<<x<<","<<y<<"]"
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e5 + 10;struct Edge {int to, next, flow;    //flow记录这条边当前的边残量
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
int dis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}bool bfs() //判断图是否连通
{queue<int>q;memset(dis, -1, sizeof(dis));dis[s] = 0;q.push(s);while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (dis[v] == -1 && edge[i].flow > 0)        //可以借助边i到达新的结点
            {dis[v] = dis[u] + 1;                    //求顶点到源点的距离编号
                q.push(v);}}}return dis[t] != -1;                                //确认是否连通
}int dfs(int u, int flow_in)
{if (u == t) return flow_in;int flow_out = 0;                                    //记录这一点实际流出的流量for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == dis[u] + 1 && edge[i].flow > 0){int flow_part = dfs(v, min(flow_in, edge[i].flow));if (flow_part == 0)continue;                //无法形成增广路flow_in -= flow_part;                        //流出了一部分,剩余可分配流入就减少了flow_out += flow_part;                        //记录这一点最大的流出
edge[i].flow -= flow_part;edge[i ^ 1].flow += flow_part;                //减少增广路上边的容量,增加其反向边的容量if (flow_in == 0)break;}}return flow_out;
}int max_flow()
{int sum = 0;while (bfs()){sum += dfs(s, inf);}return sum;
}int main() {
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow;i <= m; i++){scanf("%d%d%d", &u, &v, &flow);add(u, v, flow);add(v, u, 0);}printf("%d\n", max_flow());}return 0;
}
常用且高效的算法-Dinic

 二分图匹配

要解决这类问题,我们需要先了解什么是二分图?

二分图:一个图中的所有顶点可以分为两个集合 V,K ,其实两个集合内部的点彼此之间无边,如下图所示:(蓝色的点和红色的点分属于两个集合V,K)

然后我们回到这个题目上来,这个题目求的是最大可出战人数,实际上就是在二分图中找到两个集合中的最大匹配数,这类问题我们称之为二分图最大匹配数问题

属于网络流经典题目之一,下面说明一下建图的过程

1)由源点向集合V中每个点建一条容量为1的边

2)对于V,K集合之间存在的边e,v 为V中的点,k为K中的点,我们建一条容量为1的边,方向为 v --> k 

3)由K中每个点向汇点建一条容量为1的边

当我们将图建好了后,我们求这个图的最大流,这个最大流即为二分图最大匹配数,下面展示一下建成的图:(S代表源点,T代表汇点,蓝色的边代表容量为1的边)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e6 + 3;
const int Max = 1e6 + 10;struct Edge
{int to, next, flow;
}edge[Max << 1];;int n, m, a, b, s, t;
int head[Max], tot;
int dis[Max];
int ans;
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;ans = 0;
}void add(int u, int v, int flow)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].next = head[u];head[u] = tot++;
}bool bfs()
{memset(dis, -1, sizeof(dis));dis[s] = 0;queue<int>q;q.push(s);while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == -1 && edge[i].flow > 0){dis[v] = dis[u] + 1;if (v == t) return true;q.push(v);}}}return false;
}int dfs(int u, int flow_in)
{if (u == t) return flow_in;int flow_out = 0;for (int i = head[u]; i != -1;i = edge[i].next){int v = edge[i].to;if (dis[v] == dis[u] + 1 && edge[i].flow > 0){int flow_part = dfs(v, min(flow_in, edge[i].flow));if (flow_part == 0) continue;flow_in -= flow_part;flow_out += flow_part;edge[i].flow -= flow_part;edge[i ^ 1].flow += flow_part;if (flow_in == 0)break;}}return flow_out;
}int max_val()
{int sum = 0;while (bfs()){sum += dfs(s, inf);}return sum;
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d", &m, &n) != EOF){init();s = 0, t = n + 1;for (int i = 1;i <= m;i++){add(s, i, 1);add(i, s, 0);    //由源点向外籍飞行员建边
        }for (int i = m + 1; i <= n;i++){add(i, t, 1);add(t, i, 0);}while (scanf("%d%d", &a, &b) != EOF && a != -1 && b != -1){add(a, b, 1);add(b, a, 0);}printf("%d\n", max_val());for (int u = 1;u <= m;u++){for (int i = head[u]; i != -1;i = edge[i].next){if (edge[i].flow == 0 && edge[i].to != s && edge[i].to != t){printf("%d %d\n", u, edge[i].to);}}}}return 0;
}
飞行员配对方案-Dinic

 最小费用最大流

这类题目相比于最大流问题新增了每天边单位流量的价格,问在最大流的情况下求出最小的费用。

这类题目和最大流很想,不过也有不小区别,对于这类问题,我们为每条边建的反边的价格是每天边的相反数,如图

然后我们的算法也不再是Dinic算法了,而是用spfa或者dijkstra

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int Max = 5e3 + 10;struct Edge
{int to, rev;                    //rev记录反向边int flow, cost;;
};int n, m, k;
vector<Edge>edge[Max << 1];
int h[Max];                            //每个结点的势
int dis[Max];
int pre_node[Max], pre_edge[Max];    //前驱结点和对应边void add(int u, int v, int flow, int cost)
{edge[u].push_back({ v,(int)edge[v].size(),flow,cost });edge[v].push_back({ u,(int)edge[u].size() - 1,0,-cost });
}void min_cost_flow(int s, int t, int& min_cost, int& max_flow)
{fill(h + 1, h + 1 + n, 0);min_cost = max_flow = 0;int tot = inf;                            //源点流量无限while (tot > 0){priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > >q;memset(dis, inf, sizeof(dis));dis[s] = 0;q.push({ 0,s });while (!q.empty()){int u = q.top().second;int dist = q.top().first;q.pop();if (dis[u] < dist)continue;        //当前的距离不是最近距离for (int i = 0;i < edge[u].size(); i++){Edge &e = edge[u][i];if (edge[u][i].flow > 0 && dis[e.to] > dis[u] + e.cost + h[u] - h[e.to]){dis[e.to] = dis[u] +e.cost + h[u] - h[e.to];pre_node[e.to] = u;pre_edge[e.to] = i;q.push({ dis[e.to],e.to });}}}if (dis[t] == inf)break;            //无法增广了,就是找到答案了for (int i = 1;i <= n;i++) h[i] += dis[i];int flow = tot;                        //求这一增广路径的流量for (int i = t; i != s; i = pre_node[i])flow = min(flow, edge[pre_node[i]][pre_edge[i]].flow);for (int i = t; i != s; i = pre_node[i]){Edge& e = edge[pre_node[i]][pre_edge[i]];e.flow -= flow;edge[i][e.rev].flow += flow;}tot -= flow;max_flow += flow;min_cost += flow * h[t];}
}int main()
{
#ifdef LOCAL//freopen("input.txt", "r", stdin);//freopen("output.txt", "w", stdout);
#endifint s, t;while (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){for (int i = 1, u, v, flow, cost;i <= m;i++){scanf("%d%d%d%d", &u, &v, &flow, &cost);add(u, v, flow, cost);}int min_cost, max_flow;min_cost_flow(s, t, min_cost, max_flow);printf("%d %d\n", max_flow, min_cost);}return 0;
}
无负环图中可用的算法-dijkstra(这里给出的是可以适用于有负环的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
const int Max = 1e5 + 10;struct Edge
{int to, next;int flow, cost;
}edge[Max << 1];int n, m, s, t;
int head[Max], tot;
int dis[Max];
int pre[Max];            //记录增广路径此点的前一天边
bool vis[Max];void init()
{memset(head, -1, sizeof(head));tot = 0;
}void add(int u, int v, int flow, int cost)
{edge[tot].to = v;edge[tot].flow = flow;edge[tot].cost = cost;edge[tot].next = head[u];head[u] = tot++;edge[tot].to = u;edge[tot].flow = 0;edge[tot].cost = -cost;edge[tot].next = head[v];head[v] = tot++;
}bool spfa(int s, int t)
{memset(dis, inf, sizeof(dis));memset(vis, 0, sizeof(vis));memset(pre, -1, sizeof(pre));queue<int>q;q.push(s);dis[s] = 0;vis[s] = true;while (!q.empty()){int u = q.front();q.pop();vis[u] = false;for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (edge[i].flow > 0 && dis[v] > dis[u] + edge[i].cost){dis[v] = dis[u] + edge[i].cost;pre[v] = i;if (!vis[v]){vis[v] = true;q.push(v);}}}}return pre[t] != -1;
}void min_cost_max_flow(int s, int t, int& max_flow, int& min_cost)
{max_flow = 0;min_cost = 0;while (spfa(s, t)){int flow = inf;for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])    //沿增广路回溯edge[i^1]即为其反边
        {flow = min(flow, edge[i].flow);}for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]){edge[i].flow -= flow;edge[i ^ 1].flow += flow;min_cost += flow * edge[i].cost;}max_flow += flow;}
}int main()
{
#ifdef LOCALfreopen("input.txt", "r", stdin);freopen("output.txt", "w", stdout);
#endifwhile (scanf("%d%d%d%d", &n, &m, &s, &t) != EOF){init();for (int i = 1, u, v, flow, cost;i <= m;i++){scanf("%d%d%d%d", &u, &v, &flow, &cost);add(u, v, flow, cost);}int max_flow = 0, min_cost = 0;min_cost_max_flow(s, t, max_flow, min_cost);printf("%d %d\n", max_flow, min_cost);}return 0;
}
常用且比较高效的算法-spfa

 

转载于:https://www.cnblogs.com/winter-bamboo/p/11330082.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/391811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Tensorflow笔记(基础): 图与会话,变量

图与会话 import tensorflow as tf import os# 取消打印 cpu,gpu选择等的各种警告 # 设置TF_CPP_MIN_LOG_LEVEL 的等级,1.1.0以后设置2后 只不显示警告,之前需要设置3,但设置3不利于调试 os.environ[TF_CPP_MIN_LOG_LEVEL] 2 import time# 创建一个常量 op, 产生一个 1x2 矩阵…

css左右布局代码_如何使用CSS位置来布局网站(带有示例代码)

css左右布局代码Using CSS position to layout elements on your website can be hard to figure out. What’s the difference between absolute, relative, fixed, and sticky? It can get confusing pretty quickly.使用CSS位置来布局网站上的元素可能很困难。 绝对&#x…

redis memcached MongoDB

我们现在使用的模式是&#xff0c;对于直接的key value对需缓存的直接用memcached。对于collection类型就使用Redis。对于大数据量的内容性的东西&#xff0c;我们打算尝试用mongoDB。也正在学习neo4j&#xff0c;来应对深度搜索&#xff0c;推荐功能。 1.Memcached单个key-val…

线性代数-矩阵-转置 C和C++的实现

原理解析&#xff1a; 本节介绍矩阵的转置。矩阵的转置即将矩阵的行和列元素调换&#xff0c;即原来第二行第一列&#xff08;用C21表示&#xff0c;后同&#xff09;与第一行第二列&#xff08;C12&#xff09;元素调换位置&#xff0c;原来c31与C13调换。即cij与cji调换 。 &…

数字经济的核心是对大数据_大数据崛起为数字世界的核心润滑剂

数字经济的核心是对大数据“Information is the oil of the 21st century, and analytics is the combustion engine”.“信息是21世纪的石油&#xff0c;分析是内燃机”。 — Peter Sondergaard, Senior Vice President of Gartner Research.— Gartner研究部高级副总裁Peter…

乞力马扎罗山 海明威_我如何对海明威编辑器(一种流行的写作应用程序)进行反向工程,并从泰国的海滩上构建了自己的数据库

乞力马扎罗山 海明威I’ve been using the Hemingway App to try to improve my posts. At the same time I’ve been trying to find ideas for small projects. I came up with the idea of integrating a Hemingway style editor into a markdown editor. So I needed to fi…

leetcode 566. 重塑矩阵

在MATLAB中&#xff0c;有一个非常有用的函数 reshape&#xff0c;它可以将一个矩阵重塑为另一个大小不同的新矩阵&#xff0c;但保留其原始数据。 给出一个由二维数组表示的矩阵&#xff0c;以及两个正整数r和c&#xff0c;分别表示想要的重构的矩阵的行数和列数。 重构后的…

制作简单的WIFI干扰器

原教程链接:http://www.freebuf.com/geek/133161.htmlgithub 1.准备材料 制作需要的材料有 nodemcu开发版IIC通信 128*64 OLED液晶屏电线按钮开关万能板排针(自选)双面胶(自选)参考2.准备焊接 引脚焊接参考 oled按钮效果3.刷入固件 下载烧录工具:ESP8266Flasher.exe 下载固件:…

Snipaste截图

绘图绘色&#xff0c;描述加图片能更加说明问题的本质。今天推荐一款多功能的截图snipaste... 欣赏绘色 常见报错 解决方案&#xff1a; 下载相关的DLL即可解决&#xff0c; 请根据你操作系统的版本&#xff08;32位/64位&#xff09;&#xff0c;下载并安装相应的微软 Visual …

azure第一个月_MLOps:两个Azure管道的故事

azure第一个月Luuk van der Velden and Rik Jongerius卢克范德费尔登(Luuk van der Velden)和里克 琼格里乌斯( Rik Jongerius) 目标 (Goal) MLOps seeks to deliver fresh and reliable AI products through continuous integration, continuous training and continuous del…

firebase auth_如何使用auth和实时数据库构建Firebase Angular应用

firebase authby Zdravko Kolev通过Zdravko Kolev 如何使用auth和实时数据库构建Firebase Angular应用 (How to build a Firebase Angular app with auth and a real-time database) For a long time, I was looking for a good Portfolio web app that can help me to easily…

Mybatis—多表查询

Mybatis多表查询 一对一查询 一对一查询的模型MapperScannerConfigurer 用户表和订单表的关系为&#xff0c;一个用户有多个订单&#xff0c;一个订单只从属于一个用户 创建Order和User实体 public class Order {private int id;private Date ordertime;private double to…

VS2008 开发设计MOSS工作流 URN 注意了

最近学习MOSS 很苦恼&#xff0c;进度也很慢&#xff0c;最近在学习VS2008开发工作流&#xff0c;其中有结合INFOPATH 2007来做, 出现个BUG或者说是设置的问题,整整花了我一天工作时间&#xff0c;是这样的: 在部署的时候关于URN&#xff0c;大部分的教程都是这样的说的&#…

ArangoDB Foxx service 使用

备注&#xff1a;项目使用的是github https://github.com/arangodb-foxx/demo-hello-foxx1. git clonegit clone https://github.com/arangodb-foxx/demo-hello-foxx.git 2. 安装foxx servicefoxx-manager install demo-hello-foxx /demoapp 3. 效果自动生成的swagger 文档项目…

编译原理 数据流方程_数据科学中最可悲的方程式

编译原理 数据流方程重点 (Top highlight)Prepare a box of tissues! I’m about to drop a truth bomb about statistics and data science that’ll bring tears to your eyes.准备一盒纸巾&#xff01; 我将投放一本关于统计和数据科学的真相炸弹&#xff0c;这会让您眼泪汪…

@ConTrollerAdvice的使用

ConTrollerAdvice&#xff0c;从名字上面看是控制器增强的意思。 在javaDoc写到/*** Indicates the annotated class assists a "Controller".** <p>Serves as a specialization of {link Component Component}, allowing for* implementation classes to be a…

Mybatis—注解开发

Mybatis的注解开发 MyBatis的常用注解 这几年来注解开发越来越流行&#xff0c;Mybatis也可以使用注解开发方式&#xff0c;这样我们就可以减少编写Mapper映射文件了。 Insert&#xff1a;实现新增 Update&#xff1a;实现更新 Delete&#xff1a;实现删除 Select&#x…

道路工程结构计算软件_我从软件工程到产品管理的道路

道路工程结构计算软件by Sari Harrison莎莉哈里森(Sari Harrison) 我从软件工程到产品管理的道路 (My path from software engineering to product management) 以及一些有关如何自己做的建议 (And some advice on how to do it yourself) I am often asked how to make the m…

Vue 指令

下面列举VUE的HTML页面模板指令&#xff0c;并进行分别练习。 1. templates 2. v-if, v-for <div idapp><ol><li v-for"todo in todos>{{ todo.text}}</li></ol> </div><script>app new Vue({ el: #app, data: { return…

iOS-FMDB

2019独角兽企业重金招聘Python工程师标准>>> #import <Foundation/Foundation.h> #import <FMDatabase.h> #import "MyModel.h"interface FMDBManager : NSObject {FMDatabase *_dataBase; }(instancetype)shareInstance;- (BOOL)insert:(MyM…