当前位置: 首页 > news >正文

2021睿抗决赛 猛犸不上 Ban

在一个名叫刀塔的国家里,有一只猛犸正在到处跑着,希望能够用它的长角抛物技能来撞飞别人。已知刀塔国有 N 座城市,城市之间由 M 条道路互相连接,为了拦住这头猛犸,每条道路上设置了 Vi​ 人的团队。

这只猛犸从 S 号城市出发,它可以选择:

  1. 在不重复地经过若干条道路后回到 S 号城市;
  2. 在不重复地经过若干条道路后到达 T 号城市。

猛犸经过一条道路后,就会把路上的人全部撞飞。作为一头爱喝雪碧的仁慈的猛犸,自然希望尽可能的少撞飞人。请你帮忙计算一下在最优的选择下,最少需要撞飞多少人才能够到达目标城市?

输入格式:

输入第一行是四个正整数 N,M,S,T (2≤N≤500,1≤M≤105),表示有 N 个城市,M 条道路,猛犸从 S 号城市出发,可以选择到达 T 号城市。

接下来的 M 行,每行三个正整数 Xi​,Yi​,Vi​ (0≤Vi​≤100),表示从 Xi​ 号城市到 Yi​ 号城市有一条道路,道路上有 Vi​ 人的团队。道路可双向通行,城市编号从 1 开始,两个城市之间最多只有一条道路,且没有一条道路连接相同的城市。

数据保证两种选择里至少有一种是可行的。

输出格式:

输出两行,第一行是两个数字,分别对应上面的两种选择分别最少需要撞飞多少人。如果无论撞飞多少人都无法满足选择要求,则输出 -1

第二行是一个句子,如果第一种(回到原点)的选择比较好,就输出 Win!,否则输出Lose!

输入样例:

5 6 1 5
1 2 1
2 3 2
3 4 3
4 1 5
3 5 4
4 5 1

输出样例:

在这里给出相应的输出。例如:

11 6
Lose!

思路:

通过题目不难理解,我们要根据题意求出2种情况下的最短路并输出,再比较2种情况,输出win和lose。

     第一种情况说白了就是求 s结点自身到自身的最小自环。                                                                   第二种情况就是经典的 Dijkstra求 s 结点和 t 结点的最短路径。

先给出第二种情况的代码,这种情况的处理相对简单,直接调用模板即可求解,代码如下

到达 T 号城市的Dijkstra代码:

int dijkstra(){memset(vi,0,sizeof vi);memset(dist,0x3f,sizeof dist);priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> q;dist[s]=0;q.push({0,s});while(!q.empty()){auto it=q.top();q.pop();int u=it.second;int w=it.first;if(vi[u]){continue;}vi[u]=1;for(auto it:a[u]){int v=it.second;int w2=it.first;if(dist[v]>w+w2){dist[v]=w+w2;q.push({dist[v],v});}}}return dist[t];
}

对于第一种情况:

判断自环第一眼反应是 dfs ,从 s结点的邻接结点出发一路递归搜索到 s结点,同时一路标记路径和访问过的结点防止有重复路径和重复结点,找出所有自环,选择最短自环。然而500个结点显然会超限。

解决方法就是再走一遍Dijkstra。但上面的Dijkstra模板中会将自身结点标记,标记后的结点不再访问,如果直接从 s结点出发,走完自环在回到 s结点就会出现最后无法回环的情况,因为最初 s结点就已被标记。此时就可以参考 dfs的做法,从 s结点的邻接点出发,求邻接点到 s结点的最短距离,此时的自环权值=s结点到邻接点之间的距离+邻接点到s的最短距离(不算邻接边)。为了保证邻接点一定走的是自环,就要将邻接路径标记,也就是 path[v][s] = 1;path[s][v] = 1,如果在做松弛的过程中碰到了标记过的结点就continue ; 此时对邻接点做Dijkstra,dist数组表示邻接点到其余结点的最短距离。然后遍历s结点所有的邻接点,对每个结点求Dijkstra,套入自环权值公式求出最短自环即可。

经过若干条道路后回到 S 号城市的 Dijkstra代码:

int dijkstra(int x) {memset(vi, 0, sizeof vi);memset(dist, 0x3f, sizeof dist);//此时的dist表示x结点到其余结点的最短路径 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;dist[x] = 0;q.push({ 0,x });while (!q.empty()) {auto it = q.top();q.pop();int u = it.second;int w = it.first;if (vi[u]) {continue;}vi[u] = 1;for (auto it : a[u]) {int v = it.second;int w2 = it.first;if (path[u][v] || path[v][u]) {continue;}else {if (dist[v] > w + w2) {dist[v] = w + w2;q.push({ dist[v],v });}}}}return dist[s];
}
for (auto it : a[s]) {//自环下的最短路 int u = s;int v = it.second;int w = it.first;path[v][u] = 1;path[u][v] = 1;//默认s结点到其邻接结点的路径被访问 ans1 = min(ans1, w + dijkstra(v));path[v][u] = 0;path[u][v] = 0;
}

题目中所提到的 “不重复地经过” 会有一定的误导作用,但在Dijkstra算法中不存在求最短路但是重边的情况,而在本题中唯一的用途就是第一种情况下的 s->i,i->s

2次Dijkstra的本质相同,注意区别路径判断下的不同。

2次Dijkstra做完后根据题意输出就能AC了。

AC代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int N = 5e2 + 10;
const int INF = 0x3f3f3f3f;
vector<pair<int, int>> a[N];
int n, m, s, t;
int path[N][N];
int ans1 = INF;
int ans2;
int dist[N];
bool vi[N];
int dijkstra() {memset(vi, 0, sizeof vi);memset(dist, 0x3f, sizeof dist);priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;dist[s] = 0;q.push({ 0,s });while (!q.empty()) {auto it = q.top();q.pop();int u = it.second;int w = it.first;if (vi[u]) {continue;}vi[u] = 1;for (auto it : a[u]) {int v = it.second;int w2 = it.first;if (dist[v] > w + w2) {dist[v] = w + w2;q.push({ dist[v],v });}}}return dist[t];
}int dijkstra(int x) {memset(vi, 0, sizeof vi);memset(dist, 0x3f, sizeof dist);//此时的dist表示x结点到其余结点的最短路径 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;dist[x] = 0;q.push({ 0,x });while (!q.empty()) {auto it = q.top();q.pop();int u = it.second;int w = it.first;if (vi[u]) {continue;}vi[u] = 1;for (auto it : a[u]) {int v = it.second;int w2 = it.first;if (path[u][v] || path[v][u]) {continue;}else {if (dist[v] > w + w2) {dist[v] = w + w2;q.push({ dist[v],v });}}}}return dist[s];
}int main() {memset(path, 0, sizeof path);cin >> n >> m >> s >> t;for (int i = 1;i <= m;i++) {int u, v, w;cin >> u >> v >> w;a[u].push_back({ w,v });a[v].push_back({ w,u });}for (auto it : a[s]) {//自环下的最短路 int u = s;int v = it.second;int w = it.first;path[v][u] = 1;path[u][v] = 1;//默认s结点到其邻接结点的路径被访问 ans1 = min(ans1, w + dijkstra(v));path[v][u] = 0;path[u][v] = 0;}ans2 = dijkstra();//到 t城市的最短路 if (ans1 >= INF) {cout << "-1 ";}else {cout << ans1 << " ";}if (ans2 >= INF) {cout << "-1";}else {cout << ans2;}cout << endl;if (ans1 < ans2) {cout << "Win!" << endl;}else {cout << "Lose!" << endl;}return 0;
}

http://www.lryc.cn/news/621198.html

相关文章:

  • 十分钟学会一个算法 —— 快速排序
  • ASCII与Unicode:编码世界的奥秘
  • 【前端工具】使用 Node.js 脚本实现项目打包后自动压缩
  • C#WPF实战出真汁02--登录界面设计
  • 微服务从0到1
  • 在Ubuntu上安装Google Chrome的详细教程
  • Ubuntu下载、安装、编译指定版本python
  • 大规模调用淘宝商品详情 API 的分布式请求调度实践
  • 大规模分布式光伏并网后对电力系统的影响
  • 自动驾驶与人形机器人的技术分水岭
  • dolphinscheduler中任务输出变量的问题出现ArrayIndexOutOfBoundsException
  • 【记录】Apache SeaTunnel 系统监控信息
  • 反射在Spring IOC容器中的应用——动态创建Bean (补充)
  • Linux 上手 UDP Socket 程序编写(含完整具体demo)
  • 基于SpringBoot+Vue的房屋匹配系统(WebSocket实时通讯、协同过滤算法、地图API、Echarts图形化分析)
  • css中container和media的用法和区别
  • 【Docker】安装kafka案例
  • BGP笔记及实验
  • Windows 11操作系统 Git命令执行速度慢
  • LLM 中 语音编码与文本embeding的本质区别
  • [论文阅读] 人工智能 + 软件工程 | 从模糊到精准:模块化LLM agents(REQINONE)如何重塑SRS生成
  • OpenCV图像处理2:边界填充与平滑滤波实战
  • 数据结构之顺序表相关算法题
  • latex 中破折号的输入
  • 【PCB设计经验】3D模型在线预览!效率便捷!
  • 【浅学】tflite-micro + ESP32S3 + VScode + ESP-IDF 基于例程快速实现自己的图像分类模型训练部署全流程
  • Python学习-----3.基础语法(2)
  • 异步同步,阻塞非阻塞,reactor/proactor
  • spring boot配置es
  • CPP模板编程