L2-001 紧急救援(dijkstra算法练习)

news/2024/7/20 20:03:44 标签: 深度优先, 图论, 算法

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

首先:最简单的就是无脑DFS搜索全部情况返回最优解 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int N, M, S, D, A, B, C, road = 0, love, mind = 1 << 20;//路径 救援数
vector<int>sove(maxn);
int MAP[maxn][maxn];
deque<int>ans;
deque<int>s;
bool vis[maxn][maxn];
void DFS(int str, int end, int d, int sum)//起始 结尾 路径 救援数
{
    if (str == end && mind >= d)
    { //达到目的地 
        if(mind > d)
        {
            road = 0;
            ans = s;
            mind = d;
            love = sum;
        }
        else if(d == mind && love < sum)
        {
            love = sum;
            ans = s;
        }
        road++;
        return;
    }
    else if(str == end)return;
    for (int i = 0; i < N; i++)
    {
        if (MAP[str][i] && !vis[str][i])
        {
            vis[str][i] = true;
            s.push_back(i);
            DFS(i, end, d + MAP[str][i], sum + sove[i]);
            vis[str][i] = false;
            s.pop_back();
        }
    }
}

int main()
{
    cin >> N >> M >> S >> D;
    for (int i = 0; i < N; i++)
    {
        cin >> sove[i];
    }
    for (int i = 0; i < M; i++)
    {
        cin >> A >> B >> C;
        MAP[A][B] = MAP[B][A] = C;
    }
    DFS(S, D, 0, sove[S]);
    cout << road << " " << love << endl << S;
    while (!ans.empty())
    {
        cout << " " << ans.front();
        ans.pop_front();
    }
    return 0;
}

但是缺陷也是比较明显的,如果图中各节点的联通网十分密集的话,那我们递归的深度就很容易导致系统栈被压爆,从而得不出答案

 那么就得涉及到最短路径算法了,常见的Dijkstra或者Floyd

当然也有Bellman 和 SPFA但是不怎么常使用到(主要是个人太菜,没做过那么多题)

简单的科普Dijkstra和Floyd算法

最短路径(Dijkstra算法和Floyd算法)_法苏ovo的博客-CSDN博客

基于Floyd大多是处理任意俩点最短路径(并且效率较低)而我们这题侧重于单源路径,就采用Dijikstra进行解题

#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int maxn = 510;
int N, M, S, D, A, B, len;
vector<int>p(maxn), pre(maxn, -1), num(maxn), per(maxn), dis(maxn, INT_MAX);
// 各点的救援队数量  前置结点  从起点到该点的最短路数量 从起点到该点最短路的救援队数量 从起点到该点的最短距离 
bool vis[maxn];
struct edge
{
    int to, len;
    edge(int a, int b) : to(a), len(b) {};
};
vector<edge>e[maxn];
struct q_node
{
    int id, dis;
    q_node(int a, int b) :id(a), dis(b) {};
    bool operator< (const q_node& s)const
    {
        return dis > s.dis;
    }
};
void printf_path(int x)
{
    if (pre[x] == -1) return;
    printf_path(pre[x]);
    printf(" %d", x);
}
void dijkstra()
{
    dis[S] = 0, num[S] = 1, per[S] = p[S];
    priority_queue<q_node>Q;
    Q.emplace(S, dis[S]);
    while (!Q.empty())
    {
        auto x = Q.top();
        Q.pop();
        if (vis[x.id])continue;
        vis[x.id] = true;
        for (int i = 0; i < e[x.id].size(); i++)
        {
            auto y = e[x.id][i];//枚举邻居
            if (dis[y.to] == dis[x.id] + y.len)num[y.to] += num[x.id];
            if (dis[y.to] > dis[x.id] + y.len)num[y.to] = num[x.id];
            if ((dis[y.to] == dis[x.id] + y.len && per[y.to] < per[x.id] + p[y.to]) || dis[y.to] > dis[x.id] + y.len)
            {
                per[y.to] = per[x.id] + p[y.to];
                pre[y.to] = x.id;
                dis[y.to] = dis[x.id] + y.len;
                Q.emplace(y.to, dis[y.to]);
            }
        }
    }
}
int main()
{
    cin >> N >> M >> S >> D;
    for (int i = 0; i < N; i++)cin >> p[i];
    while (M--)
    {
        cin >> A >> B >> len;
        e[A].emplace_back(B, len);
        e[B].emplace_back(A, len);
    }
    dijkstra();
    cout << num[D] << " " << per[D] << endl << S;
    printf_path(D);
    return 0;
}

Dijkstra算法练习

公交线路 (nowcoder.com)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
int n,m,s,t,A,B,len;
struct edge
{
    int form,to,len;
    edge(int a,int b,int c) : form(a),to(b),len(c){};
};
vector<edge>e[maxn];
vector<int>dis(maxn,0x3f3f3f3f),pre(maxn);
bool vis[maxn];
struct q_node
{
    int id,dis;
    q_node(int a,int b):id(a),dis(b){};
    bool operator < (const q_node& s)const
    {
        return dis > s.dis;
    }
};
void dijkstra()
{
    dis[s] = 0;
    priority_queue<q_node>Q;
    Q.emplace(s,dis[s]);
    while(!Q.empty())
    {
        auto x = Q.top();
        Q.pop();
        if(vis[x.id])continue;
        vis[x.id] = true;
        for(int i = 0;i < e[x.id].size();i++)
        {
            auto y = e[x.id][i];
            if(vis[y.to])continue;
            if(dis[y.to] > x.dis + y.len)
            {
                dis[y.to] = x.dis + y.len;
                pre[y.to] = x.id;
                Q.emplace(y.to,dis[y.to]);
            }
        }
    }
}
int main()
{
    cin.tie(0)->sync_with_stdio(false);
    cin >> n >> m >> s >> t;
    while(m--)
    {
        cin >> A >> B >> len;
        e[A].emplace_back(A,B,len);
        e[B].emplace_back(B,A,len);
    }
    dijkstra();
    dis[t] == 0x3f3f3f3f ? cout << -1 << endl : cout << dis[t] << endl;
    return 0;
}


http://www.niftyadmin.cn/n/359435.html

相关文章

认识 Protobuf 及其简单使用

文章目录 一、序列化与反序列化1.1 序列化1.2 反序列化1.3 序列化与反序列化的使用场景 二、初识 Protobuf三、Protobuf 的安装四、Protobuf 的使用案例4.1 创建并编写 .proto 文件的基本规范与语法4.2 编译 .proto 文件4.3 序列化与反序列化的使用 五、总结 ProtoBuf 的使用特…

【大数据之Hive】二、Hive安装

Hive安装部署&#xff08;最小化部署&#xff09; 安装部署Hive&#xff08;最小化只用于本机测试环境中&#xff0c;不可用于生产环境&#xff09;&#xff0c;并运行。 步骤&#xff1a; &#xff08;1&#xff09;把apache-hive-3.1.3-bin.tar.gz解压到/opt/module/目录下&…

aop实现自定义注解

注解简单知识 关键字 自定义注解的关键字是interface 参数类型 自定义注解的参数类型&#xff1a;八大基础类型、String、枚举、注解&#xff0c;还可以是以上类型对应的数组 如果只有一个成员变量&#xff0c;名字叫value 注解赋值 如果定义了成员变量&#xff0c;必须…

Java经典笔试题—day13

Java经典笔试题—day13 &#x1f50e;选择题&#x1f50e;编程题&#x1f36d;参数解析&#x1f36d;跳石板 &#x1f50e;结尾 &#x1f50e;选择题 (1)一个关系数据库文件中的各条记录 &#xff08;&#xff09; A. 前后顺序不能任意颠倒&#xff0c;一定要按照输入的顺序排…

MyBatis源码学习四之二级缓存

MyBatis源码学习四之二级缓存 MyBatis的缓存使用的也比较多&#xff0c;而缓存的都实现了一个父类的接口Cache。 一、加载缓存类PerputualCache public static void main(String[] args) {InputStream inputStream null;try {inputStream Resources.getResourceAsStream(&q…

C++第一章:开始

开始目录 引言一、开发环境和参考书籍二、一个简单的C程序三、初识输入和输出标准输入输出对象 四、注释五、控制流while循环for循环 六、数量不定数据的输入七、C 缩进和格式八、类简介使用一个类书店处理书籍信息程序 九、术语表 引言 C在人们的眼中通常是“复杂”一词的代表…

linux0.12-10-6-tty_io.c

[539页] 10-6 tty_io.c程序 10-6-1 功能描述 每个tty设备有3个缓冲队列&#xff0c;分别是读缓冲队列(read_q)、写缓冲队列(write_q)和辅助缓冲队列(secondary)&#xff0c;定义在tty_struct结构中(include/linux/tty.h)。 对于每个缓冲队列&#xff0c;读操作是从缓冲队列的…

文件包含的本质、预处理符号、# vs ##

何为头文件&#xff1f; 在C语言中&#xff0c;文件包含是一种常见的编程技术&#xff0c;它允许程序员在一个源文件中使用另一个源文件中的函数或变量。 文件包含通常使用#include预处理指令来实现。#include指令告诉预处理器将文件的内容插入到当前文件的指定位置中。 例如&a…