一题带你写出图论算法模板!!!

news2024/11/15 13:22:00

这题是道基础的图论算法题目 

注释很重要!!!!!!!

在做这道题之前,我们先了解一下基础的图论算法吧!!!

 

1.floyd:

 

 这样可以求出所有点到任意一点的最短路径和距离

dijkstra:

最短路问题考察的是我们如何抽象成一个模型

图论的题侧重点在于抽象

难点在建图!!!!

2.朴素Dijstra算法

Dijkstra算法算是贪心思想实现的,首先把起点到所有点的距离存下来找个最短的,然后松弛一次再找出最短的,所谓的松弛操作就是,遍历一遍看通过刚刚找到的距离最短的点作为中转站会不会更近,如果更近了就更新距离,这样把所有的点找遍之后就存下了起点到其他所有点的最短距离

3.dijkstra算法(堆优化,c++直接用STL优先队列)

能使用的核心是堆中出来的点一定是最小的,且不会被更新的

4.spfa算法(没有负环就可以用)

可以用于适合dijkstra解决的问题

floyd方法:

class Solution {
public:
    int dist[1100][1100];
    void floyd(int n)
    {
        //floyd本质是试点探测法
        for(int k = 0;k < n;k++)
          for(int i = 0;i < n;i++)
           for(int j = 0;j < n;j++)
           {
               //试点探测
               dist[i][j] = min(dist[i][j],dist[i][k] + dist[k][j]);
           }
    }
    int ans[1110];
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) 
    {
       //这题一看求的就是多源最短路
       //计算出当前点到所有点的最短距离,小于distance距离的点加入到当前点的数组的中
       //多源最短路有floyd算法,最常用的算法
       //也可以用单源最短路算法spfa和dijkstra,bellmanford(一般不用,复杂度有点高)
       //1.dijkstra算出当前点到所有点的距离,小于distance距离的点加入到当前点的数组的中
       //再遍历下一个点,往返加入

       int m = edges.size();
       memset(dist,0x3f,sizeof(dist));//初始化为无穷,方便后续试点判断的时候,不把无穷的点加入
       //无向图
       for(int i = 0;i < m;i++)
       {
          int a = edges[i][0];
          int b = edges[i][1];
          int c = edges[i][2];
          dist[a][b] = c;
          dist[b][a] = c;
          dist[a][a] = 0;
          dist[b][b] = 0;
       }
       
       floyd(n);
       int min_val = 0x3f3f3f3f;
       for(int i = 0;i < n;i++)
       {
           cout<<i<<" ";
          for(int j = 0;j < n;j++)
          {
            if(j == i) continue;
            if(dist[i][j] <= distanceThreshold) ans[i]++;
          }
          min_val = min(ans[i],min_val);
          cout<<ans[i]<<endl;
       }
       int res = -0x3f3f3f3f;
       for(int i = 0;i < n;i++)
       {
           if(ans[i] == min_val && res < i) res = i;
       }
       return res;
    }
};

spfa方法:
 

class Solution {
public:
    int h[11100],w[11100],ne[11100],e[11100],idx = 0;
    int dist[11100];
    void add(int a,int b,int c)
    {
        e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
    }
    queue<int> q;
    int st[1100];
    void spfa(int start)
    {
         dist[start] = 0;
         q.push(start);//队列里放着要被更新的点,这个点要去松弛边
         st[start] = 1;
         while(!q.empty())
         { 
            auto t = q.front();
            q.pop();
            st[t] = 0;//该点出队更新其他点(松弛边)
            for(int i = h[t];i != -1;i = ne[i])
            {
               int b = e[i];
               int c = w[i];
               if(dist[b] > dist[t] + c)
               {
                   dist[b] = dist[t] + c;
                   if(!st[b]) 
                   {
                     q.push(b);//如果该点不在队列里面,并且连接该点的边又被更新,那么我们一定要加入到队列,再更新一次
                     st[b] = 1;
                   }
               }
            }
         }
         //题目没有负权边
    }
    int ans[1100];
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
        memset(h,-1,sizeof(h));
        int m = edges.size();
        for(int i = 0;i < m;i++)
        {
           int a = edges[i][0];
           int b = edges[i][1];
           int c = edges[i][2];
           add(a,b,c);
           add(b,a,c);
        }
        
        int min_val = 0x3f3f3f3f;
        for(int i = 0;i < n;i++)
        {
           int start = i;
           memset(dist,0x3f,sizeof(dist));
           memset(st,0,sizeof(st));
           spfa(start);

           for(int j = 0;j < n;j++)
           {
              if(j == start) continue;
              if(dist[j] <= distanceThreshold) ans[start]++;
           }
           cout<<start<<" "<<ans[start]<<endl;
           min_val = min(ans[start],min_val);
        }
       cout<<min_val<<endl;
       int res = -0x3f3f3f3f;
       for(int i = 0;i < n;i++)
       {
           if(ans[i] == min_val && res < i) res = i;
       }
       return res;
    }
};

dijkstra方法:

class Solution {
public:
    int h[11100],w[11100],ne[11100],e[11100],idx = 0;
    int dist[11100];
    void add(int a,int b,int c)
    {
        e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
    }
    //st数组保存的是已经被拿来更新过的点
    //我们每次取的就是,从未被更新过的点集中选出一个离更新过的点的点集(距离点集中的源点最近)最近的点
    //更新过的点的点集我们记为V,未更新过的点的点集记为E
    int st[11000];
    void dijkstra(int start,int n)
    {
        dist[start] = 0;
        for(int i = 0;i < n;i++)
        {  
          int t = -1;
           for(int j = 0;j < n;j++)
           {
              if(!st[j] && (t == -1 || dist[t] > dist[j])) //要拿出的点必须是未更新过的点集中的点,
              //并且是离V的点集(距离点集中的源点),也就是距离源点距离最短的点
              {
                t = j;
              }
           }

           st[t]  = 1;

              for(int i = h[t];i != -1;i = ne[i])//用t去更新邻边
              {
                 int b = e[i];
                 int c = w[i];
                 dist[b] = min(dist[b],dist[t] + c); 
              }
        }
    }
    int ans[1100];
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
        memset(h,-1,sizeof(h));
        int m = edges.size();
        for(int i = 0;i < m;i++)
        {
           int a = edges[i][0];
           int b = edges[i][1];
           int c = edges[i][2];
           add(a,b,c);
           add(b,a,c);
        }
        
        int min_val = 0x3f3f3f3f;
        for(int i = 0;i < n;i++)
        {
           int start = i;
           memset(dist,0x3f,sizeof(dist));
           memset(st,0,sizeof(st));
           dijkstra(start,n);

           for(int j = 0;j < n;j++)
           {
              if(j == start) continue;
              if(dist[j] <= distanceThreshold) ans[start]++;
           }
           cout<<start<<" "<<ans[start]<<endl;
           min_val = min(ans[start],min_val);
        }
       cout<<min_val<<endl;
       int res = -0x3f3f3f3f;
       for(int i = 0;i < n;i++)
       {
           if(ans[i] == min_val && res < i) res = i;
       }
       return res;
    }
};

模板题:

#include <iostream>
//因为题目给出500个点,100000条边,说明是个稠密图
//所以我们用邻接矩阵去存储
//朴素dijkstra算法
//三步骤
//1.初始化dist[1] = 0,其余的为正无穷,可以用0x3f3f3f表示
//2for循环n次
//3.遍历dist数组,找到一个节点,找到一个距离最短的值,假设最短的值的节点为j
//每次从 「未求出最短路径的点」中 取出 距离距离起点 最小路径的点,并把这个最短路径的点标记
//4.遍历从i节点后继的所有节点,更新节点,例如i节点后面是j,如果dist[j] > dist[i] + w
//w:i到j的边的距离,那么就更新dist[j] = dist[i] + w;

//1 3 4,1 3 4,1 3 4,重复循环完,1步骤是遍历所有节点 
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 510;
int n,m;
int g[N][N],dist[N];//g是邻接矩阵,dist表示起点到当前节点的最短距离,下标就是顶点
//又因为这里我们是带权的,权不一样,所以g二维数组里面的元素表示的是从前一个顶点到这个
//点的边权(距离),每行每列的下标都代表顶点,元素是边权,边权为0就是两顶点没边
bool st[N];//默认为false,找到这个点的最短路径的话,就标记下来,不用再找了
//算法模板中第一个节点实际上被再次遍历了同时初始化了下一层的所有节点距离
int dijkstra()
{
    dist[1] = 0;//源点的距离我们默认为1
    for(int i = 1;i <= n;i++)
    {
        int t = -1;//因为dijkstra算法不适用于负权边,所以我们用这个判断可以把第一个点
        //加入
        for(int j = 1;j <= n;j++)//遍历数组找到从当前顶点直达的最小的路径
        //为什么可以直接找到直达的,因为我们初始化时,不可达到的距离我们设为正无穷
        //所以说每次最多能达到初始化过dist的下标,没初始化过的其实就不会去执行t = j了
        {
            if(!st[j] && (t == -1 || dist[t] > dist[j]))//后面的或号我们叫短路操作
            //dist[t] > dist[j]确保了不是直接连通的顶点不会去执行这条语句
            {
                t = j;
            }
        }
        st[t] = true;
        //算法模板中第一个节点实际上被再次遍历了同时初始化了下一层的所有节点距离
        for(int j = 1;j <=n;j++)//用t去更新最短距离,枚举经过确定t顶点到直达的顶点的距离
        //并初始化
        //0x3f3f3f确保了不会执行不是直达的,不过我们还是要遍历n次,可能他由t出发的直达的
        //边有n条,因为稠密图是假设起点是st那么st的出边可能就有n条边,那么遍历完需要n个起点
        //稀疏图假设起点是st,出边最多可能有n条边,但是因为n和m相同,所以我们只是o(N)
        {
            dist[j] = min(dist[j],dist[t] + g[t][j]);
        }
    }
    if(dist[n] == 0x3f3f3f3f) return -1;
    else return dist[n];
}
int main()
{
    memset(dist,0x3f,sizeof dist);
    memset(g,0x3f,sizeof g);
    cin>>n>>m;
    for(int i = 0;i < m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b] = min(g[a][b],c);
    }
    printf("%d",dijkstra());
    return 0;
}

dijkstra(堆优化版)方法:

class Solution {
public:
    int h[11100],w[11100],ne[11100],e[11100],idx = 0;
    int dist[11100];
    void add(int a,int b,int c)
    {
        e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx++;
    }
    //st数组保存的是已经被拿来更新过的点
    //我们每次取的就是,从未被更新过的点集中选出一个离更新过的点的点集(距离点集中的源点最近)最近的点
    //更新过的点的点集我们记为V,未更新过的点的点集记为E
    int st[11000];
    typedef pair<int,int> PII;
    priority_queue<PII,vector<PII>,greater<PII>> heap;
    void dijkstra_heap(int start,int n)
    {
        dist[start] = 0;
        heap.push({0,start});

        while(!heap.empty())
        {
            auto t = heap.top();//选出距离源点最小的点,按照dist(距离)排序
            int dist_u = t.first;
            int u = t.second;
            heap.pop();
            //如果该点是已经之前更新过的点(已经选中去松弛过的点),那不能被松弛,跳过
            if(st[u]) continue;
            else st[u] = 1;

            for(int i = h[u];i != -1;i = ne[i])
            {
               int b = e[i];
               int c = w[i];
               if(dist[b] > dist[u] + w[i])
               {
                   //如果该点被更新了,那么要再加入更新一下
                   dist[b] = dist[u] +w[i];//因为该边被更新了,那么他的邻边也需要更新
                   heap.push({dist[b],b});
               }
            }
        }
    }
    int ans[1100];
    int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {
        memset(h,-1,sizeof(h));
        int m = edges.size();
        for(int i = 0;i < m;i++)
        {
           int a = edges[i][0];
           int b = edges[i][1];
           int c = edges[i][2];
           add(a,b,c);
           add(b,a,c);
        }
        
        int min_val = 0x3f3f3f3f;
        for(int i = 0;i < n;i++)
        {
           int start = i;
           memset(dist,0x3f,sizeof(dist));
           memset(st,0,sizeof(st));
           dijkstra_heap(start,n);

           for(int j = 0;j < n;j++)
           {
              if(j == start) continue;
              if(dist[j] <= distanceThreshold) ans[start]++;
           }
           min_val = min(ans[start],min_val);
        }
       cout<<min_val<<endl;
       int res = -0x3f3f3f3f;
       for(int i = 0;i < n;i++)
       {
           if(ans[i] == min_val && res < i) res = i;
       }
       return res;
    }
};

模板题:

#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
typedef pair<int,int> pll;
const int N = 200010;
int h[N],e[N],ne[N],idx;
int n,m,w[N],dist[N];
bool st[N];
void add(int a,int b,int c)
{
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
int dijkstra_2()
{
    dist[1] = 0;//初始话为0
    priority_queue<pll,vector<pll>,greater<pll>> heap;
    //加入第一个
    heap.push({0,1});//左边是顶点,右边是起点到当前顶点的距离
    while(!heap.empty())
    {
        auto t =heap.top();//大根堆,拿出最小的
        heap.pop();
        int k = t.second,dis = t.first;//k代表当前顶点
        if(st[k]) continue;//如果枚举过了就不用在枚举了
            st[k] = true;//
        for(int i = h[k];i != - 1;i = ne[i])//枚举当前最短距离的顶点,找到最小的边,加入
        {
            int j = e[i];//找到当前顶点直达的顶点
            if(dist[j] > dist[k] + w[i])//初始化当前最短的顶点直达的边的距离
            {
                dist[j] = dist[k] + w[i];
                heap.push({dist[j],j});//把顶点和距离加入,优先队列会维护这个队列的
            }
        }
    }
    if(dist[n] == 0x3f3f3f3f) return 0;
    else return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(h,-1,sizeof h);
    memset(dist,0x3f,sizeof dist);
    for(int i = 0;i < m;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    if(dijkstra_2() == 0) printf("-1\n");
    else printf("%d",dijkstra_2());
    return 0;
}

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

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

相关文章

了解一下知识付费系统的开发流程和关键技术点

知识付费系统的开发既涉及到前端用户体验&#xff0c;又需要强大的后端支持和复杂的付费逻辑。在这篇文章中&#xff0c;我们将深入探讨知识付费系统的开发流程和关键技术点&#xff0c;并提供一些相关的技术代码示例。 1. 需求分析和规划&#xff1a; 在着手开发知识付费系…

day21_mysql

今日内容 零、 复习昨日 第一阶段: Java基础知识(会编程,懂编程) 第二阶段: Web开发(前端,后端,数据库) 一、MySQL 一、引言 二、数据库 2.1 概念 ​ 数据库是“按照数据结构来组织、存储和管理数据的仓库。是一个长期存储在计算机内的、有组织的、有共享的、统一管理的数据集合…

搭建成功simulink-stm32硬件在环开发环境

本次实验所使用的软件版本和硬件平台参数如下&#xff1a; Matlab版本: 2021b STM32硬件平台&#xff1a;YF_STM32_Alpha 1R4(参考自STM32 Nucleo F103RB官方开发板) YF_STM32_Alpha开发板 STM32 Nucleo F103RB 开发板 2.1 STM32硬件支持包下载 读者朋友平时使用的是和谐版M…

基于springboot实现体育场馆运营平台项目【项目源码】

基于springboot实现体育场馆运营管理系统演示 系统开发平台 在该数码论坛系统中&#xff0c;Eclipse能给用户提供更多的方便&#xff0c;其特点一是方便学习&#xff0c;方便快捷&#xff1b;二是有非常大的信息储存量&#xff0c;主要功能是用在对数据库中查询和编程。其功能…

基于SpringBoot+Vue的在线外卖管理系统

基于SpringBootVue的在线外卖管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 下单界面 登录界面 商家界面 摘要 本文介绍了一种基于Spring Boot和…

【vue实战项目】通用管理系统:api封装、404页

前言 本文为博主的vue实战小项目系列中的第三篇&#xff0c;很适合后端或者才入门的小伙伴看&#xff0c;一个前端项目从0到1的保姆级教学。前面的内容&#xff1a; 【vue实战项目】通用管理系统&#xff1a;登录页-CSDN博客 【vue实战项目】通用管理系统&#xff1a;封装to…

k8s之Helm

理论&#xff1a; 什么是 He lm 在没使用 helm 之前&#xff0c;向 kubernetes 部署应用&#xff0c;我们要依次部署 deployment、svc 等&#xff0c;步骤较繁琐。 况且随着很多项目微服务化&#xff0c;复杂的应用在容器中部署以及管理显得较为复杂&#xff0c;helm 通过打包…

球星马布里申请香港高才通计划落户香港拿身份!谈谈香港身份的好处!

球星马布里申请香港高才通计划落户香港拿身份&#xff01;谈谈香港身份的好处&#xff01; 据香港政府新闻网14日消息&#xff0c;前美国职业篮球联赛球员马布里&#xff0c;日前向香港人才服务办公室递交高端人才通行证计划的申请。香港劳工及福利局局长孙玉菡与他会面&#x…

并发编程之生产者消费者模型

什么是生产者消费者模型 生产者消费者模型是多线程中一个比较典型的模型。 打个比方&#xff1a;你是一个客户&#xff0c;你去超市里买火腿肠。 这段话中的 "你"就是消费者&#xff0c; 那么给超市提供火腿肠的供货商就是生产者。超市呢&#xff1f;超市是不是被…

可怕!.Net 8正式发布了,.Net野心确实不小!

随着三天.NET Conf 2023的会议结束了&#xff0c;.Net 8正式发布了。 .Net 8是官方号称有史以来性能最快的一个版本了。 .Net 8 增加了数以千计的性能、稳定性和安全性改进&#xff0c;以及平台和工具增强功能&#xff0c;有助于提高开发人员的工作效率和创新速度。 反正就是…

Oneid 图计算思路

一、前文 oneid 是用户画像的核心&#xff0c;此文提供图计算的具体方案。 二、方案 注意事项&#xff1a; 1. 业务存在解绑信息&#xff0c;当不与其他业务系统产生关联时&#xff0c;沿用旧oneid。 2. oneid 需要自增&#xff0c;下游系统会用到bitmap等数据类型&#xff0…

学习c#的第十三天

目录 C# 多态性 静态多态性 函数重载 运算符重载 动态多态性 virtual 和 abstract 抽象方法和虚方法的区别 重载(overload)和重写(override) 隐藏方法 C# 多态性 多态是同一个行为具有多个不同表现形式或形态的能力。 多态性意味着有多重形式。在面向对象编程范式中…

自由曲线与曲面 -计算机图形学

目录 自由曲线与曲面 函数的连续性 &#xff08;1&#xff09;参数连续性 &#xff08;2&#xff09;几何连续性 bezier 曲线 Bernstein基函数 *公式看不懂&#xff0c;带几个数进去看看&#xff0c;你就更好地可以看到这个公式的本质了 凸包性质 仿射不变性 …

PyCharm 【unsupported Python 3.1】

PyCharm2020.1版本&#xff0c;当添加虚拟环境发生异常&#xff1a; 原因&#xff1a;Pycharm版本低了&#xff01;不支持配置的虚拟环境版本 解决&#xff1a;下载PyCharm2021.1版本&#xff0c;进行配置成功&#xff01;

mysql之搭建MMM架构实现高可用

实验目的 解决mysql的主从服务器单点故障问题&#xff0c;实现高可用 实验思路 实验条件&#xff1a; 主机名 作用 IP地址 组件 mysql1 master01 20.0.0.13 mysql服务、mysql-mmm mysql2 masert02 20.0.0.23 mysql服务、mysql-mmm mysql3 slave01 20.0.0.33 …

C# 使用Microsoft.Office.Interop.Excel库操作Excel

1.在NuGet管理包中搜索&#xff1a;Microsoft.Office.Interop.Excel&#xff0c;如下图红色标记处所示&#xff0c;进行安装 2. 安装完成后&#xff0c;在程序中引入命名空间如下所示&#xff1a; using Microsoft.Office.Interop.Excel; //第一步 添加excel第三方库 usi…

kubernetes集群编排——prometheus监控

部署prometheus 创建项目仓库并上传镜像 编写配置文件 [rootk8s2 values]# vim prometheus-values.yaml alertmanager:alertmanagerSpec:image:repository: prometheus/alertmanagertag: v0.24.0 grafana:enabled: trueimage:repository: grafana/grafanatag: 9.0.6service:typ…

【开发问题解决方法记录】01.dian

一些问题记录 新增角色失败&#xff1a;Error: Ajax 调用为Execute Server-Side Code返回了服务器错误ORA-01722: 无效数字。 【问题原因】&#xff1a;CREATE_BY(NUMBER类型)应该存入USER_ID(NUMBER类型)而非USER_NAME&#xff08;NVARCHAR2类型&#xff09; 【解决方法】将…

一篇文章让你真正搞懂epoll机制

目录 1.epoll简介 2.epoll实现原理 3.创建epoll文件 4.增加&#xff0c;删除&#xff0c;修改epoll事件 5.epoll事件就绪 6.epoll编程流程 7.epoll常见问题&#xff1f; 1.epoll简介 epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;它能显著提高程…

一篇文章让你搞懂 MySQL 的锁

一篇文章让你搞懂 MySQL 的锁 1、并发问题的解决方案2、MySQL的各类型锁2.1、从数据操作的类型划分 (读锁、写锁)2.2、从数据操作的粒度划分2.2.1、表锁2.2.1.1、表级别的S 锁、X 锁2.2.1.2、意向锁&#xff08;IS、IX&#xff09;2.2.1.3、自增锁2.2.1.4、元数据锁 2.2.2、行锁…