【蓝桥杯】49362.《视频相关度计算》

news2024/12/19 6:32:44

视频相关性计算

问题描述

小蓝作为异世界最大流媒体网站 LanTube 的高级算法工程师,他想要实现更加精准的视频推荐服务来满足用户的喜好。
其中,**“视频的相关性”**是一个重要指标,它代表了两个视频 A 到 B 的关联程度,记作 f(A, B)。
现在我们给出两个视频 相关性 的定义:若 A 视频,在通过一系列相关联视频构成的路径中,可以关联到 B 视频,则称此条路径为 相关路径,而相关性 f(A,B)等于每一条相关路径上最小相关性的总和。
例如:视频 A 与视频 B,C 相关,相关性f(A,B)= 10,f(A,C)= 4;视频 B 与视频D 相关,f(B,D)=5;视频 C 与视频 D 相关,f(C,D)=3。则在相关路径A→B→D 中,最小相关性为5,在相关路径A→C→D 中,最小相关性为 3,则 f(A,D)=5+3=8。
现在给出了 N 部视频,序号依次为1~ N。并已知 M 条关于第a部视频到第b部视频相关性f(a,b),其中a≠b。求第 S 部视频到第 T 部视频的相关性。

注明:原题说法有误,f(A,C)= 2,f(C,D)=3,则在相关路径A→C→D 中,最小相关性应该为 2,则 f(A,D)=5+2=7。所以7才是正确的最小相关性。此处为了不引起误解,将f(A,C)=2修改为f(A,C)=4。

输入格式

第一行包含四个正整数 N,M,S,T,代表有 N 个视频,有 M 对视频的相关性,求第 S 和第 T 部视频相关性。
接着下面 M 行,每行有三个整数 α,b, f(a,b),代表第 α 部到第 b部视频相关性为 f(a,b)。

输出格式

输出一个正整数,代表第 S 和第 T 部视频相关性。

输入样例
7 8 2 7
2 1 50
2 3 40
1 4 40
3 4 50
4 5 20
4 6 40
5 7 30
6 7 40
输出样例
60

说明

题目中存在两条相关路径
·2→1→4→5→7,该路径中最小相关性为 20。
·2→3→4→6→7,该路径中最小相关性为 40。
综上,第2个节点到第7个节点的相关性为 60。

数据范围

对于所有数据,保证 2<N<100,1 <M<1000,1≤S≠T≤N,1≤a,b<N,f(a,b)< 108

题目解析

这道题本质上是图的路径搜索问题。
假设有一个图,其中有N个节点,M条边,已知出发点S和结束点T,求经过S和T的路径有多少条,这些路径即为“相关路径”。
遍历这些相关路径,求得每条路径上最小权重值,该值即为该路径的最小相关性。
将每条路径的最小相关性累加。
如下图所示:
在这里插入图片描述
根据题目的要求,题目中存在两条相关路径
·2→1→4→5→7,该路径中最小的权重的边为4→5,权重为 20。
·2→3→4→6→7,该路径中最小的权重的边为2→3,权重为 40。
则2→7的相关性为两条路径的最小权重之和=20+40=60。

解题思路

整体思路概述

代码在整体上采用网络流算法中的 Dinic 算法来解决视频相关性计算的问题,本质上是将视频看作图中的节点,视频之间的相关性看作边的权重,通过寻找从起始视频节点(S)到目标视频节点(T)的所有相关路径,并计算每条路径上的最小相关性之和来得到最终结果。

数据结构与初始化部分

定义常量与全局变量:

定义了 INF 表示一个极大值(通过 sys.maxsize 获取),用于表示流量的无穷大概念(在网络流算法里常用)。

定义了 N 和 M 分别作为节点数量和边数量的上限值,初始化了 head(用于存储邻接表的表头指针)、d(用于存储节点的距离标号)、e(存储边的信息的列表)、k(边的索引计数)以及 n、m、s、t(分别对应输入的节点数、边数、起始节点、目标节点,后续会重新赋值)等全局变量。

定义节点类 Node:
用于表示图中的边,包含了起点 u、终点 v、边的流量(即为相关性权重)flow 以及指向下一条边的指针 next,通过这个类可以方便地构建图的邻接表结构。

初始化函数 add:
用于向图中添加边,每添加一条边,实际上会在邻接表中添加两条互为反向的边(一条正向表示从 u 到 v 的边,另一条反向边流量初始化为 0,这是网络流算法处理反向边的常见做法),同时更新 k(边的索引)以及对应的邻接表表头 head。

核心算法部分(基于 Dinic 算法)

广度优先搜索函数 bfs:

首先将所有节点的距离标号 d 初始化为 0,然后将起始节点 s 加入队列 que,并标记其距离标号 d[s] 为 1。

接着进入循环,不断从队列中取出节点 x,遍历其所有出边(通过邻接表结构,从 head[x] 开始),对于那些未被标记距离标号(d[e[i].v] == 0)且边的流量(权重)大于 0 的邻接节点 e[i].v,将其加入队列,并更新其距离标号为当前节点距离标号加 1(d[e[i].v] = d[x] + 1)。

只要在搜索过程中发现目标节点 t 的距离标号被更新了,就表示找到了从 s 到 t 的一条增广路径,返回 True;否则当队列为空还没找到时,返回 False。这个过程实际上是在构建分层图,为后续的深度优先搜索找增广路做准备。

深度优先搜索函数 dfs:

以当前节点 u 和可流经的流量 flow 作为参数,当 u 等于目标节点 t 时,说明找到了一条从 s 到 t 的完整路径,直接返回当前流量 flow。

否则,尝试沿着距离标号递增(d[e[i].v] == d[u] + 1)且边的流量大于 0 的边进行深度优先搜索,调用 dfs 函数递归地找下一层节点,每次传递的流量是当前剩余流量 res 和当前边的流量 e[i].flow 中的较小值(min(res, e[i].flow))。

如果递归返回的流量 temp 为 0,表示当前边无法继续拓展增广路了,将对应节点的距离标号置为 0(d[e[i].v] = 0);然后更新剩余流量 res,同时减少当前边正向边的流量、增加反向边的流量(这是网络流算法中反向边的作用体现,用于回退流量和寻找其他增广路)。

最后返回本次从 u 出发实际能推送的流量(flow - res)。

Dinic 算法主函数 dinic:

在一个循环中不断调用 bfs 函数构建分层图,如果存在增广路(bfs 返回 True),则进入内层循环不断调用 dfs 函数找增广路并更新最大流(这里的最大流值累加对应相关性的计算,每次找到一条增广路就相当于找到了一条相关路径,并把路径上能通过的流量累加起来,类比于相关路径的最小相关性累加),直到找不到增广路(dfs 返回 0)为止,最后返回累加得到的相关性总和(也就是最大流的值)。

主程序部分

输入处理:
通过 input().split() 获取输入的节点数 n、边数 m、起始节点 s 和目标节点 t,然后循环 m 次,每次读取一条边的起点 u、终点 v 和相关性权重 f,并调用 add 函数将边添加到图中。
结果输出:
调用 dinic 函数计算并直接输出第 S 部视频到第 T 部视频的相关性结果。

代码实现

import os
import sys
# 引入双端队列,用于后续广度优先搜索中存储节点
from collections import deque

# 定义一个极大值,用于表示类似无穷大的概念,例如在网络流中表示流量无上限等情况
INF = sys.maxsize

# 定义节点数量的上限值,这里是一个预估的较大值,方便处理不同规模的图数据
N = 105
# 定义边数量的上限值,同样是预估的较大值,便于应对不同输入情况
M = 1005

# head列表用于存储邻接表的表头指针,初始化为 -1,表示每个节点初始时没有出边
head = [-1] * N
# d列表用于存储节点的距离标号,初始化为0,后续在广度优先搜索分层图构建中会更新
d = [0] * N
# e列表用于存储图的边信息,每条边用一个Node类实例表示
e = []
# k用于记录边的索引,方便在邻接表中添加和查找边
k = 0
# n, m, s, t分别用于存储输入的节点数、边数、起始节点、目标节点,初始先赋值为0,后续会重新读取输入进行赋值
n, m, s, t = 0, 0, 0, 0

# 定义Node类,用于表示图中的边
class Node:
    def __init__(self, u, v, flow, next):
        # 边的起点
        self.u = u
        # 边的终点
        self.v = v
        # 边的流量(在这里可以类比视频相关性中的权重)
        self.flow = flow
        # 指向下一条边的指针,用于构建邻接表结构
        self.next = next

# 向图中添加边的函数
def add(u, v, f):
    global k
    # 创建一条从u到v的边,将其添加到边列表e中,并更新对应的邻接表表头指针等信息
    e.append(Node(u, v, f, head[u]))
    head[u] = k
    k += 1
    # 同时添加反向边(在网络流算法中反向边用于回退流量等操作),流量初始化为0
    e.append(Node(v, u, 0, head[v]))
    head[v] = k
    k += 1

# 广度优先搜索函数,用于构建分层图,找到从起始节点s到其他节点的最短距离(以边的数量衡量)
def bfs():
    # 初始化所有节点的距离标号为0
    for i in range(N):
        d[i] = 0
    # 创建队列,并将起始节点s加入队列
    que = deque([s])
    # 标记起始节点s的距离标号为1,表示距离起始点的距离为1(按边的数量算)
    d[s] = 1
    # 只要队列不为空,就进行循环,不断扩展已访问的节点范围
    while que:
        # 取出队列头部的节点
        x = que.popleft()
        # 获取当前节点x的邻接表表头指针
        i = head[x]
        # 遍历当前节点x的所有出边
        while i!= -1:
            # 如果邻接节点e[i].v还未被标记距离标号(即还未访问过)且当前边的流量大于0(表示可以通过这条边继续扩展路径)
            if not d[e[i].v] and e[i].flow > 0:
                # 将邻接节点加入队列
                que.append(e[i].v)
                # 更新邻接节点的距离标号,为当前节点距离标号加1
                d[e[i].v] = d[x] + 1
            # 获取下一条边的指针,继续遍历当前节点的其他出边
            i = e[i].next
        # 如果在搜索过程中,目标节点t的距离标号已经被更新了(说明找到了从s到t的一条路径),则返回True
        if d[t]:
            return True
    # 如果队列为空还未找到到目标节点t的路径,则返回False
    return False

# 深度优先搜索函数,用于在分层图的基础上,沿着距离标号递增的路径寻找增广路,并更新流量
def dfs(u, flow):
    # 如果当前节点u就是目标节点t,说明找到了一条从起始节点到目标节点的完整路径,返回当前可流经的流量
    if u == t:
        return flow
    # res用于记录当前从节点u出发还能分配的剩余流量,初始为传入的flow
    res = flow
    # 获取当前节点u的邻接表表头指针
    i = head[u]
    # 遍历当前节点u的所有出边,只要还有剩余流量可以分配且还有出边可遍历
    while i!= -1 and res > 0:
        # 如果邻接节点的距离标号等于当前节点距离标号加1(符合分层图中距离递增的要求,即沿着增广路的方向)且当前边的流量大于0(表示可以通过这条边推送流量)
        if d[e[i].v] == d[u] + 1 and e[i].flow > 0:
            # 递归调用dfs函数,尝试沿着这条边向邻接节点推送流量,推送的流量取剩余流量res和当前边流量e[i].flow中的较小值
            temp = dfs(e[i].v, min(res, e[i].flow))
            # 如果递归返回的流量为0,说明从邻接节点那边无法继续推送流量了,将邻接节点的距离标号置为0(相当于标记此路不通,后续搜索不再考虑)
            if temp == 0:
                d[e[i].v] = 0
            # 更新剩余流量,减去已经推送出去的流量temp
            res -= temp
            # 减少当前边正向边的流量,表示已经推送了部分流量过去
            e[i].flow -= temp
            # 增加当前边反向边的流量,这是网络流算法中利用反向边回退流量、寻找其他增广路的关键操作
            e[i ^ 1].flow += temp
        # 获取下一条边的指针,继续遍历当前节点的其他出边
        i = e[i].next
    # 返回从当前节点u出发实际能推送出去的流量(即初始传入的流量减去剩余未推送出去的流量)
    return flow - res

# Dinic算法主函数,通过不断调用bfs构建分层图,然后调用dfs寻找增广路来计算最大流(在这里类比视频相关性总和)
def dinic():
    ans = 0
    # 只要通过bfs能构建出分层图(即存在增广路),就进入循环
    while bfs():
        # 在每次构建好分层图后,不断调用dfs寻找增广路并更新最大流,直到找不到增广路(dfs返回0)为止
        while True:
            temp = dfs(s, INF)
            if temp == 0:
                break
            ans += temp
    return ans

if __name__ == "__main__":
    # 读取输入的节点数、边数、起始节点、目标节点
    n, m, s, t = map(int, input().split())
    # 循环读取每一条边的信息,并调用add函数将边添加到图中
    for _ in range(m):
        u, v, f = map(int, input().split())
        add(u, v, f)
    
    # 调用dinic函数计算并输出第S部视频到第T部视频的相关性(通过网络流算法计算得到的类似最大流的值)
    print(dinic())

代码运行结果

>>> 
7 8 2 7
2 1 50
2 3 40
1 4 40
3 4 50
4 5 20
4 6 40
5 7 30
6 7 40
60
>>> 

在这里插入图片描述

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

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

相关文章

ASP.NET|日常开发中数据集合详解

ASP.NET&#xff5c;日常开发中数据集合详解 前言一、数组&#xff08;Array&#xff09;1.1 定义和基本概念1.2 数组的操作 二、列表&#xff08;List<T>&#xff09;2.1 特点和优势2.2 常用操作 三、字典&#xff08;Dictionary<K, V>&#xff09;3.1 概念和用途…

如何将多张图片合并为一个pdf?多张图片合并成一个PDF文件的方法

如何将多张图片合并为一个pdf&#xff1f;当我们需要将多张图片合并为一个PDF文件时&#xff0c;通常是因为我们希望将这些图片整理成一个统一的文档&#xff0c;方便查看、分享或打印。无论是工作中需要提交的报告、学生们需要整理的作业&#xff0c;还是个人收藏的照片、旅行…

【html网页页面013】html+css制作节日主题圣诞节网页含视频、留言表单(独创首发-5页面附效果及源码)

节日主题圣诞节网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果完整效果(5页)&#xff1a;代码目录结构&#xff1a;page1、首页page2、庆祝page3、影响page4、起源page5、留言板 &#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取圣诞…

直播预告 | 蓝卓生态说,解锁supOS在化工领域的无限可能

生态是蓝卓生命力的体现&#xff0c;为全方位赋能生态伙伴使用supOS并从中获益&#xff0c;蓝卓打造生态说系列栏目&#xff0c;通过生态沙龙、直播对话、案例剖析、产品解读等&#xff0c;持续展现“12N”的智能工厂创新路径&#xff0c;加速推进工业数字化转型。 嘉宾介绍 朱…

java对子网掩码的转换

一般的子网掩码展示为点分十进制形式&#xff0c;如&#xff1a;255.255.255.0&#xff0c;但有时因为业务需要&#xff0c;我们需要转换成对应的数字&#xff0c;以及数字转成点分十进制&#xff0c;所以整理了java的方法可以进行两者的互相转换 1、点分十进制转数字 public…

亚马逊-用表格创建多变体商品

引言 当我们使用“月亮树选品软件”找到一款不错的产品时&#xff0c;我们会延续这个产品的优点&#xff0c;并对其进行改良。改良之后&#xff0c;我们需要将产品上架到亚马逊平台&#xff0c;以测试这个产品的市场表现。然而&#xff0c;许多亚马逊卖家觉得上传多变体商品这…

使用C#在目录层次结构中搜索文件以查找目标字符串

例程以递归方式搜索目录层次结构中的文件以查找目标字符串。它可以搜索几乎任何类型的文件&#xff0c;即使它不包含 Windows 理解的文本。例如&#xff0c;它可以搜索 DLL 和可执行文件以查看它们是否恰好包含字符串。 下面的代码中显示的ListFiles 方法完成了大部分工作。 …

【深度学习总结】使用PDF构建RAG:结合Langchain和通义千问

【深度学习总结】使用PDF构建RAG&#xff1a;结合Langchain和通义千问 使用平台&#xff1a;趋动云&#xff0c;注册送算力 前言 在大型语言模型&#xff08;LLMs&#xff09;应用领域&#xff0c;我们面临着大量挑战&#xff0c;从特定领域知识的匮乏到信息准确性的窘境&am…

P8772 [蓝桥杯 2022 省 A] 求和

题目描述&#xff1a; 解题思路&#xff1a; 首先这题我们可以直接用两个for循环嵌套来控制两个变量来求值&#xff0c;但是这样做时间复杂度高。这里我们用到了一个前缀和差的方法。通过for循环变量第一个变量&#xff0c;用和差的方法的到第二个量&#xff0c;这样就只用了一…

Flux Tools 结构简析

Flux Tools 结构简析 BFL 这次一共发布了 Canny、Depth、Redux、Fill 四个 Tools 模型系列&#xff0c;分别对应我们熟悉的 ControlNets、Image Variation&#xff08;IP Adapter&#xff09;和 Inpainting 三种图片条件控制方法。虽然实现功能是相同的&#xff0c;但是其具体…

什么是芯片电阻

有人把Chip Resistor翻译成“芯片电阻”&#xff0c;我觉得翻译成“贴片电阻”或“片状电阻”更合适。有些厂商也称之为”电阻片”&#xff0c;英文写作Resistor Chip。比如&#xff1a;Thick film resistor chips&#xff08;厚膜电阻片&#xff09;、Thin film resistor chip…

【Linux】深入理解进程信号机制:信号的产生、捕获与阻塞

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 时间不语&#xff0c;却回答了所有问题 目录 &#x1f4da;前言 &#x1f4da;一、信号的本质 &#x1f4d6;1.异步通信 &#x1f4d6;2.信…

模具生产过程中的标签使用流程图

①NFC芯片嵌入周转筐&#xff0c;通过读卡器读取CK_Label_v3的数据&#xff0c;并将这些信息上传至服务器进行存储&#xff1b; ②服务器随后与客户的WMS&#xff08;仓库管理系统&#xff09;进行交互&#xff0c;记录和同步注塑机的原始数据&#xff1b; ③当周转筐内的模具…

【AIGC安全】CCF-CV企业交流会直播回顾:探寻AI安全治理,共筑可信AI未来

文章目录 一、活动背景&#xff1a;AI技术快速发展与安全治理需求迫切二、论坛内容金耀辉&#xff1a;智能共生时代&#xff1a;平衡生成式AI的创新与风险何延哲&#xff1a;人工智能安全检测评估的逻辑和要点谢洪涛&#xff1a;面向特定人物深度伪造视频的主动防御与被动检测技…

Cesium 无人机航线规划(区域航线)

区域航线&#xff0c;即划定一片区域一键巡查 这里选择点几个点&#xff0c;形成的区域内计算规划航线

【SH】Ubuntu Server 24搭建Web服务器访问Python程序研发笔记

文章目录 说个问题写个方案一、安装Ubuntu Server二、安装Web服务器采用Nginx服务器 三、安装Python及依赖创建项目虚拟环境 四、安装Python Web框架采用Flask框架创建和运行Flask应用&#xff08;以后的重点&#xff09; 五、安装WSGI服务器采用Gunicorn 六、配置Nginx七、验证…

SpringBoot如何实现缓存预热?

缓存预热是指在 Spring Boot 项目启动时&#xff0c;预先将数据加载到缓存系统&#xff08;如 Redis&#xff09;中的一种机制。 那么问题来了&#xff0c;在 Spring Boot 项目启动之后&#xff0c;在什么时候&#xff1f;在哪里可以将数据加载到缓存系统呢&#xff1f; 实现…

贪心算法 part01

class Solution { public:int maxSubArray(vector<int>& nums) {int result INT32_MIN;int count 0;for (int i 0; i < nums.size(); i) {count nums[i];if (count > result) { // 取区间累计的最大值&#xff08;相当于不断确定最大子序终止位置&#xff…

Redis应用—6.热key探测设计与实践

大纲 1.热key引发的巨大风险 2.以往热key问题怎么解决 3.热key进内存后的优势 4.热key探测关键指标 5.热key探测框架JdHotkey的简介 6.热key探测框架JdHotkey的组成 7.热key探测框架JdHotkey的工作流程 8.热key探测框架JdHotkey的性能表现 9.关于热key探测框架JdHotke…

海外招聘丨卢森堡大学—人工智能和机器学习中的 PI 用于图像分析

雇主简介 卢森堡大学立志成为欧洲最受推崇的大学之一&#xff0c;具有鲜明的国际化、多语言和跨学科特色。 她促进研究和教学的相互影响&#xff0c;与国家息息相关&#xff0c;因其在特定领域的研究和教学而闻名于世&#xff0c;并成为当代欧洲高等教育的创新典范。 她的核…