当前位置: 首页 > 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.dtcms.com/a/330963.html

相关文章:

  • diffusers库学习--pipeline,模型,调度器的基础使用
  • 深入解析Prompt缓存机制:原理、优化与实践经验
  • Centos9傻瓜式linux部署CRMEB 开源商城系统(PHP)
  • 流式数据服务端怎么传给前端,前端怎么接收?
  • Keil 微库(MicroLib)深度解析
  • USB 3.0 协议层 包定义
  • 微软对传统网页设计工具在2010年停止开发
  • Sql server 命令行和控制台使用二三事
  • web网站开发,在线%射击比赛成绩管理%系统开发demo,基于html,css,jquery,python,django,model,orm,mysql数据库
  • 一文讲透Go语言并发模型
  • Pytest本地插件定制及发布指南
  • Redis7学习--十大数据类型 bitmap、Hyperloglog、GEO、Stream、bitfield
  • PAT乙级_1073 多选题常见计分法_Python_AC解法_含疑难点
  • mysql查询中的filesort是指什么
  • Linux软件编程:进程和线程
  • 火山引擎数智平台发布 Data Agent“一客一策“与 AI 数据湖“算子广场“
  • 【Python】新手入门:什么是python字符编码?python标识符?什么是pyhon保留字?
  • 【数据集介绍】多种飞机检测的YOLO数据集介绍
  • 服务器数据恢复—误删服务器卷数据的数据恢复案例
  • 配置docker pull走http代理
  • 集成电路学习:什么是Video Processing视频处理
  • 网络原理-HTTP
  • 【论文阅读】基于多变量CNN模型的可穿戴外骨骼机器人人体运动活动识别
  • Notepad++插件开发实战:从零打造效率工具
  • 边缘光效果加流光效果
  • 从0开始跟小甲鱼C语言视频使用linux一步步学习C语言(持续更新)8.14
  • 测试开发的社区:测试之家
  • 从根源到生态:Apache Doris 与 StarRocks 的深度对比 —— 论开源基因与长期价值的优越性
  • lib.dom.d.ts
  • 速通C++类型转换(代码+注释)