【深圳大学算法设计与分析】 实验六 最大流应用问题 FF -> EK -> Dinic

news2024/11/18 1:38:57

目录

一、实验目的:

二、内容:棒球赛问题

三、实验要求

四、提交要求

————————

问题分析解释:

————————

算法简解:

Ford–Fulkerson 增广

Edmonds–Karp 算法

Dinic算法

Dinic和EK的区别:

代码:


一、实验目的:

  1. 掌握最大流算法思想。
  2. 学会用最大流算法求解应用问题。

二、内容:棒球赛问题

网络流和棒球赛淘汰问题 | Matrix67: The Aha Moments

1996 年 9 月 10 日,《旧金山纪事报》的体育版上登载了《巨人队正式告别 NL 西区比赛》一文,宣布了旧金山巨人队输掉比赛的消息。当时,圣地亚哥教士队凭借 80 场胜利暂列西区比赛第一,旧金山巨人队只赢得了 59 场比赛,要想追上圣地亚哥教士队,至少还得再赢 21 场比赛才行。然而,根据赛程安排,巨人队只剩下 20 场比赛没打了,因而彻底与冠军无缘(摘自http://www.matrix67.com/blog/archives/5190)。

  有趣的是,报社可能没有发现,其实在两天以前,也就是 1996 年 9 月 8 日,巨人队就已经没有夺冠的可能了。那一天,圣地亚哥教士队还只有 78 场胜利,与洛杉矶道奇队暂时并列第一。此时的巨人队仍然是 59 场胜利,但还有 22 场比赛没打。因而,表面上看起来,巨人队似乎仍有夺冠的可能。然而,根据赛程安排

,圣地亚哥教士队和洛杉矶道奇队互相之间还有 7 场比赛要打,其中必有一方会获得至少 4 场胜利,从而拿到 82 胜的总分;即使巨人队剩下的 22 场比赛全胜,也只能得到 81 胜。由此可见,巨人队再怎么努力,也不能获得冠军了。

  在美国职业棒球的例行赛中,每个球队都要打 162 场比赛(对手包括但不限于同一分区里的其他队伍,和同一队伍也往往会有多次交手),所胜场数最多者为该分区的冠军;如果有并列第一的情况,则用加赛决出冠军。在比赛过程中,如果我们发现,某支球队无论如何都已经不可能以第一名或者并列第一名的成绩结束比赛,那么这支球队就提前被淘汰了(虽然它还要继续打下去)。从上面的例子中可以看出,发现并且证明一个球队已经告败,有时并不是一件容易的事。

关于这个事情有一个有趣的故事,下面是一段对话:

“看到上周报纸上关于爱因斯坦的那篇文章了吗?……有记者请他算出三角比赛的数学公式。你知道,一支球队赢得了很多剩余的比赛,其他球队则赢这个赢了那个。这个比赛到底有多少种可能性?哪个球队更有优势?”

“他到底知道吗?”

“显然他知道的也不多。上周五他选择道奇队没有选巨人队。”

上面的表是四个球队的比赛情况,现在的问题是哪些球队有机会以最多的胜利结束这个赛季?可以看到蒙特利尔队因最多只能取得 80 场胜利而被淘汰,但亚特兰大队已经取得 83 场胜利,蒙特利尔队因为wi + ri < wj 而被淘汰。费城队可以赢83场,但仍然会被淘汰。 。 。如果亚特兰大输掉一场比赛,那么其他球队就会赢一场。所以答案不仅取决于已经赢了多少场比赛,还取决于他们的对手是谁。

请利用最大流算法给出上面这个棒球问题的求解方法。

三、实验要求

1. 解释流网络的构造原理。

2. 解释为什么最大流能解决这个问题。

3.给出上面四个球队的求解结果。

4. 尽可能实验优化的最大流算法。

四、提交要求

1. 在blackboard提交电子版实验报告,注意实验报告的书写,整体排版。

2. 实验报告的实验步骤部分需详细给出算法思想与实现代码之间的关系解释,不可直接粘贴代码(直接粘贴代码者视为该部分内容缺失)。

3. 实验报告中要求证明该算法的关键定理,并说明这些定理所起的作用。

4. 源代码作为实验报告附件上传。

5. 在实验课需要现场运行验证并讲解PPT。

————————

问题分析解释:

如果把每个单位的流量理解成一个一个的胜局,那么网络流也就可以理解为这些胜局的来源和去向。


编号:

要判断一个队伍是否有机会以最多的胜利结束这个赛季,只需让他全胜,然后分配其他队伍,看能否是最大值。

即在其余队伍都不超过这只队伍最高得分的前提下,比赛能否比完,如果能比完,这支队伍确实有机会获胜。

如果比不完(即此时无论如何分配,不管谁赢,都会超过这只队伍),那么这支队伍就无法取胜。所以我们可以用最大流来解决这个问题

让Atl接下来比赛全胜:

可以流完。

————————

算法简解:

最大流 - OI Wiki

一条从源点 s 到汇点 t 的路径称为增广路

对于一条增广路,给每一条边 都加上等量的流量,以令整个网络的流量增加,这一过程被称为增广。

最大流的求解可以被视为若干次增广分别得到的流的叠加。

—————

Ford–Fulkerson 增广

Ford–Fulkerson 增广是计算最大流的一类算法的总称。该方法运用贪心的思想,通过寻找增广路来更新并求解最大流。

步骤:

1.寻找任意一条增广路

2.取增广路中最小容量作为本次增广流量

3.添加反向边——负流量 (反向边容量为0,此时 $$容量 - 负流量$$ 为正值)

时间复杂度:

上界:总边数*求得的最大流

对于反向边的理解:

我们当前的增广并不是最优的,需要调整,调整即把原来走过去的一部分“反悔”重新选择路径。反向边实则实现了这样的方式——别的增广路也能走这里,那么之前的可以换个路径走。所以可以走更多的增广路。

Edmonds–Karp 算法

13-3: Edmonds-Karp Algorithm 寻找网络最大流_哔哩哔哩_bilibili

Edmonds–Karp 算法其实就是优化了 Ford–Fulkerson 增广,在最开始找增广时,不去随意找,而是用Bfs找最短的。

时间复杂度为O(|V||E|)

迭代次数:在最坏的情况下,每次 BFS 都会减少至少一条边的容量,因此算法的迭代次数不会超过边数 E。

由于每次 BFS 的时间复杂度是 O(V + E),并且迭代次数最多是 E,因此 Edmonds-Karp 算法的总时间复杂度是 O(E * (V + E))

Dinic算法

13-4: Dinic's Algorithm 寻找网络最大流_哔哩哔哩_bilibili

分层概念:

BFS 来构建分层图。

Dinic:

时间复杂度最坏为 O(m*n*n)

最多需要n-1轮,每轮BFS+DFS是O(m*n)

Dinic 算法会重复执行 BFS 和 DFS,直到无法找到增广路径为止。在最坏的情况下,每次迭代都会减少至少一条边的容量,因此迭代次数不会超过 E。

Dinic和EK的区别:

Dinic比EK更优,是因为Dinic一次分层后会把一层的增广路径都给找到。

代码:

直接粘的OI WIKI的板子:

#include <bits/stdc++.h>
using namespace std;
const int INF = std::numeric_limits<int>::max();

#define maxn 250
#define N 250
#define INF 0x3f3f3f3f
#define ll long long

struct Edge {
    int from, to, cap, flow;

    Edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
};
struct EK {
    int n, m;             // n:点数,m:边数
    vector<Edge> edges;   // edges:所有边的集合
    vector<int> G[maxn];  // G:点 x -> x 的所有边在 edges 中的下标
    int a[maxn], p[maxn];  // a:点 x -> BFS 过程中最近接近点 x 的边给它的最大流
                           // p:点 x -> BFS 过程中最近接近点 x 的边

    void init(int n) {
        for (int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from, int to, int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    int Maxflow(int s, int t) {
        int flow = 0;
        for (;;) {
            memset(a, 0, sizeof(a));
            queue<int> Q;
            Q.push(s);
            a[s] = INF;
            while (!Q.empty()) {
                int x = Q.front();
                Q.pop();
                for (int i = 0; i < G[x].size(); i++) {  // 遍历以 x 作为起点的边
                    Edge& e = edges[G[x][i]];
                    if (!a[e.to] && e.cap > e.flow) {
                        p[e.to] = G[x][i];  // G[x][i] 是最近接近点 e.to 的边
                        a[e.to] =
                            min(a[x], e.cap - e.flow);  // 最近接近点 e.to 的边赋给它的流
                        Q.push(e.to);
                    }
                }
                if (a[t]) break;  // 如果汇点接受到了流,就退出 BFS
            }
            if (!a[t])
                break;  // 如果汇点没有接受到流,说明源点和汇点不在同一个连通分量上
            for (int u = t; u != s;
                u = edges[p[u]].from) {  // 通过 u 追寻 BFS 过程中 s -> t 的路径
                edges[p[u]].flow += a[t];      // 增加路径上边的 flow 值
                edges[p[u] ^ 1].flow -= a[t];  // 减小反向路径的 flow 值
            }
            flow += a[t];
        }
        return flow;
    }
};
struct MF {
    struct edge {
        int v, nxt, cap, flow;
    } e[N];

    int fir[N], cnt = 0;

    int n = 249, S = 1, T = 12;
    ll maxflow = 0;
    int dep[N], cur[N];

    void init() {
        memset(fir, -1, sizeof fir);
        cnt = 0;
    }

    void addedge(int u, int v, int w) {
        e[cnt] = { v, fir[u], w, 0 };
        fir[u] = cnt++;
        e[cnt] = { u, fir[v], 0, 0 };
        fir[v] = cnt++;
    }

    bool bfs() {
        queue<int> q;
        memset(dep, 0, sizeof(int) * (n + 1));

        dep[S] = 1;
        q.push(S);
        while (q.size()) {
            int u = q.front();
            q.pop();
            for (int i = fir[u]; ~i; i = e[i].nxt) {
                int v = e[i].v;
                if ((!dep[v]) && (e[i].cap > e[i].flow)) {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                }
            }
        }
        return dep[T];
    }

    int dfs(int u, int flow) {
        if ((u == T) || (!flow)) return flow;

        int ret = 0;
        for (int& i = cur[u]; ~i; i = e[i].nxt) {
            int v = e[i].v, d;
            if ((dep[v] == dep[u] + 1) &&
                (d = dfs(v, min(flow - ret, e[i].cap - e[i].flow)))) {
                ret += d;
                e[i].flow += d;
                e[i ^ 1].flow -= d;
                if (ret == flow) return ret;
            }
        }
        return ret;
    }

    void dinic() {
        while (bfs()) {
            memcpy(cur, fir, sizeof(int) * (N));
            maxflow += dfs(S, INF);
        }
    }
} mf;
int main() 
{
    int n;
    cin >> n;
    mf.init();
    for (int i = 0; i < n; i++)
    {
        int f, t, c;
        cin >> f >> t >> c;
        mf.addedge(f, t, c);
    }
    mf.dinic();
    cout << "最大流:" << mf.maxflow << endl;
    return 0;
}

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

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

相关文章

DDPM(Denoising Diffusion Probabilistic Models)

DDPM&#xff08;Denoising Diffusion Probabilistic Models&#xff09; 笔记来源&#xff1a; 1.Denoising Diffusion Probabilistic Models 2.大白话AI | 图像生成模型DDPM | 扩散模型 | 生成模型 | 概率扩散去噪生成模型 3.pytorch-stable-diffusion 扩散模型正向过程&am…

Kafka-服务端-网络层-源码流程

整体架构如下所示&#xff1a; responseQueue不在RequestChannel中&#xff0c;在Processor中&#xff0c;每个Processor内部有一个responseQueue 客户端发送的请求被Acceptor转发给Processor处理处理器将请求放到RequestChannel的requestQueue中KafkaRequestHandler取出reque…

易校网校园综合跑腿小程序源码修复运营版

简介&#xff1a; 易校网校园综合跑腿小程序源码修复运营版&#xff0c;带服务端客户端前端文档说明。 源码安装方法&#xff1a; 需要准备小程序服务号 服务器 备案域名 校园网跑腿小程序源码需要准备 1.小程序 2.服务器&#xff08;推荐配置2h4g3m&#xff09; 3.域名…

安卓实现微信聊天气泡

一搜没一个能用的&#xff0c;我来&#xff1a; 布局文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xml…

第十二章 路由器静态路由配置

实验目标 掌握静态路由的配置方法和技巧&#xff1b; 掌握通过静态路由方式实现网络的连通性&#xff1b; 熟悉广域网线缆的链接方式&#xff1b; 实验背景 学校有新旧两个校区&#xff0c; 每个校区是一个独立的局域网&#xff0c; 为了使新旧校区能够正常相互…

CTFHUB-SSRF-上传文件

通过file协议访问flag.php文件内容 ?urlfile:///var/www/html/flag.php 右键查看页面源代码&#xff0c;发现需要从内部上传一个文件这样才能正常获取到flag ?urlhttp://127.0.0.1/flag.php 发现无提交按钮&#xff0c;构造一个 <input type"submit" name&qu…

HarmonyOS开发探索:使用Snapshot Insight分析ArkTS内存问题

识别内存问题 当怀疑应用存在内存问题的时候&#xff0c;首先使用DevEco Profiler的Allocation Insight来度量内存在问题场景下的大小变化以及整体趋势&#xff0c;初步定界问题出现的位置&#xff08;Native Heap/ArkTS Heap/dev等&#xff09;。 在初步识别内存问题出现的位置…

阿里云物联网应用层开发:第二部分,云产品流转

文章目录 哔哩哔哩视频教程1、云产品流转概述2、我们需要创建多少个云产品流转&#xff1f;3、阿里云物联网平台产品云流转实现3-1 创建数据源3-2 创建数据目的3-2 创建解析器,并关联数据、编写脚本 哔哩哔哩视频教程 【阿里云物联网综合开发&#xff0c;STM32ESP8266微信小程…

2024年道路运输安全员(企业管理人员)备考题库资料。

46.危险货物道路运输随车携带的单据&#xff0c;下列选项不属于的是&#xff08;&#xff09;。 A.道路运输危险货物安全卡 B.运单或者电子运单 C.道路危险货物运输从业资格证 D.车辆检测报告 答案&#xff1a;D 47.危险货物运输驾驶人员在24小时内实际驾驶车辆时间累计不…

opengl箱子的显示

VS环境配置&#xff1a; /JMC /ifcOutput "Debug\" /GS /analyze- /W3 /Zc:wchar_t /I"D:\Template\glfwtemplate\glfwtemplate\assimp" /I"D:\Template\glfwtemplate\glfwtemplate\glm" /I"D:\Template\glfwtemplate\glfwtemplate\LearnOp…

接口测试流程及测试点!

一、什么时候开展接口测试 1.项目处于开发阶段&#xff0c;前后端联调接口是否请求的通&#xff1f;&#xff08;对应数据库增删改查&#xff09;--开发自测 2.有接口需求文档&#xff0c;开发已完成联调&#xff08;可以转测&#xff09;&#xff0c;功能测试展开之前 3.专…

ctfshow-web入门-命令执行(web75-web77)

目录 1、web75 2、web76 3、web77 1、web75 使用 glob 协议绕过 open_basedir&#xff0c;读取根目录下的文件&#xff0c;payload&#xff1a; c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). ); } ex…

如何用大模型RAG做医疗问答系统

代码参考 https://github.com/honeyandme/RAGQnASystemhttps://github.com/LongxingTan/open-retrievals TLDR if 疾病症状 in entities and 疾病 not in entities:sql_q "match (a:疾病)-[r:疾病的症状]->(b:疾病症状 {名称:%s}) return a.名称" % (entitie…

Cosine 余弦相似度并行计算的数学原理与Python实现

背景 Cosine 我在LLM与RAG系列课程已经讲了很多次了&#xff0c;这里不在熬述&#xff0c;它在LLM分析中&#xff0c;尤其是在语义相似度的计算中至关重要&#xff0c;在dot attention机制中&#xff0c;也会看到他的身影。这里讲的是纯数学上的运算与python是如何运用相关库进…

鸿蒙开发Ability Kit(程序访问控制):【向用户申请单次授权】

申请使用受限权限 受限开放的权限通常是不允许三方应用申请的。当应用在申请权限来访问必要的资源时&#xff0c;发现部分权限的等级比应用APL等级高&#xff0c;开发者可以选择通过ACL方式来解决等级不匹配的问题&#xff0c;从而使用受限权限。 举例说明&#xff0c;如果应…

代码随想录算法训练营第55天(py)| 单调栈 | 42. 接雨水*、84.柱状图中最大的矩形

42. 接雨水* 力扣链接 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 思路1 暴力 按列来计算。每一列雨水的高度&#xff0c;取决于&#xff0c;该列 左侧最高的柱子和右侧最高的柱子中&#xff0c;…

【记录】IDEA2023的激活与安装

前言&#xff1a; 记录IDEA2023的激活与安装 第一步&#xff1a;官网下载安装包&#xff1a; 下载地址&#xff1a;https://www.jetbrains.com/idea/download/other.html 这个最好选择2023版本&#xff0c;用着很nice。 安装步骤就不详解了&#xff0c;无脑下一步就可以了…

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数 0. 引言1. 关于m_pcolor2. 关于m_image3. 关于m_shadedrelief4. 关于m_hatch5. 结语 0. 引言 本篇介绍下m_map中区域填充函数&#xff08;m_hatch&#xff09;、绘制伪彩色图…

C++多态~~的两个特殊情况

目录 1.多态的概念 2.简单认识 &#xff08;1&#xff09;一个案例 &#xff08;2&#xff09;多态的两个满足条件 &#xff08;3&#xff09;虚函数的重写 &#xff08;4&#xff09;两个特殊情况 1.多态的概念 &#xff08;1&#xff09;多态就是多种形态&#xff1b; …

某腾X滑块验证码

⚠️前言⚠️ 本文仅用于学术交流。 学习探讨逆向知识,欢迎私信共享学习心得。 如有侵权,联系博主删除。 请勿商用,否则后果自负。 网址 aHR0cHM6Ly9jbG91ZC50ZW5jZW50LmNvbS9wcm9kdWN0L2NhcHRjaGE= 1. 先整体分析一下 1_1. 验证码信息下发接口 cap_union_prehandle ua:…