典型的dijkstra HDU 2680 Choose the best route

news/2024/11/23 3:20:55/

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2680

题目大意:一个笨蛋要坐车去朋友家,但坐车呕吐,所以想在最短时间内到达。

测试数据意思:

第一行三个数:n(车站的个数,n<1000)  |  m(代表车站之间所有线路的总个数)  | s(代表离朋友家最近的车站)

下面有m行:   p q t   意思是:一条从p到q的线路,花费t时间

m行之后有个数字:w (代表可以在开始时搭乘的车站)

下面w个数W1,W2....Ww就是车站的编号

解题报告:

从题意看,我们可以反过来看。看成是:从要到达的车站s到可以搭车的车站w...反正不管正着看,还是反着看,就是求点到点的最短路径问题,而且没有负权值(为什么要没有负权值呢,下面讲),明显用dijkstra(混蛋,不懂的话,看下数据结构书p187)。

思路:你想啊笨蛋

如果存在一条从i到j的最短路经(pi,.......pk,pj),那么(p1.......pk)必然是一条从i到k的最短路经,否则的话,(pi.....pk,pj)不可能成为从i到j的最短路径。为了求出最短路径,dijkstra提出了一个按路径长度递增的次序产生最短路径的算法;

什么意思呢? 大致意思就是:对于原顶点V0,首先选择其直接相邻的顶点中最短的顶点Vi,那么可知:由V0经过Vi到与Vi直接相邻的顶点Vj的最短距离dis[j] = min(    map[V0][j] ,    dis[i] + map[i][j]) 这句最重要了,什么意思呢?就是要么直接到,要么转一下再到。(觉得很熟悉,在动态规划或贪心时,见过)

所以:

假设存在G=<V,E>,源顶点为V0,U={V0},dis[i]记录V0到i的最短距离 ,map[i][j]记录i到j的距离

1.从V-U中dis[i]值最小的顶点i,将i加入到U中;

2.更新与i直接相邻顶点的dis值。(dist[j]=min{map[V0][j],dis[i]+map[i][j]})

3.直到U=V,停止。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define M 2002    //这个地方太坑爸爸了,按照题目上我设成20002居然没执行函数体,直接return 啦
#define N 1002    //这些看题目数据范围
#define INF 999999
int n,m,s;
int map[M][M];    //map[i][j]表示i到j的权值
int dis[N];        //dis[i] 表示原点s到i的距离
int visit[N];      //顶点是否被访问过
void dijkstra(int s)
{int i,j,k = 0;int min;memset(visit,0,sizeof(visit));  //初始时都没被访问过for(i = 1; i <=n; i++){dis[i] = map[s][i];}visit[s] = 1;  //第一个顶点即原点,被访问dis[s] = 0; //s到s 即为0for(i = 1; i < n; i++){min = INF;//找到最小的for (j = 1; j <= n; j++){if ( !visit[j] && dis[j] < min){min = dis[j];k = j;   //最小的顶点}}if (min == INF){break;}visit[k] = 1; //k顶点被访问//这里就是比较:直接到还是转一下再到//我猜,你个笨蛋肯定会问:不能转多下吗?//答曰:从源点一个一个向外扩展,具有最优子结构。每个dis[i]都保留着从s到i的最短距离。转多下的情况把它分解开,就知道了for(j = 1; j <= n; j++)   {if ( !visit[j] && dis[j] > dis[k] + map[k][j]){dis[j] = dis[k] + map[k][j];}}}return ;
}
int main()
{int i,j;int p,q,t,w;int  minx ,ww;while ( scanf("%d %d %d",&n,&m,&s) != EOF){memset(dis,0,sizeof(dis));for (i = 1; i<= n; i++)for(j = 1; j <= n; j ++){map[i][j] = INF;}for(i = 1; i <= m; i++){scanf("%d%d%d",&p,&q,&t);if(t < map[q][p])     //题目上明明说的t <= 1000的,尼玛不加就错。以后保险起见要加啊map[q][p] = t;   //注意啊啊啊啊啊啊,因为是把S(目的地)看成源点,所以有向图方向要反过来啊}dijkstra(s);scanf("%d",&w);minx = INF;for (i = 1; i <=w; i++ )  //找到最小的dis{scanf("%d",&ww);if (minx > dis[ww]){minx = dis[ww];}}if ( minx != INF){printf("%d\n",minx);}else{printf("-1\n");}}return 0;
}

然后解释:为什么dijkstra为什么不能有负权值???

比如:相邻顶点i,j这两个顶点之间的边map[i][j] < 0,那么当V0到Vi的最短路径为dis[i]时,那dis[j]怎么算呢?

按我们的dijkstra算法该是dist[j]=min{map[V0][j],dis[i]+map[i][j]}那么明显,当计算dis[i]时,i顶点已经加入了最短路径的集合U中,U中的最短路径及其长度是不会再变更的,因为visit[i] 已经被访问过变为1。。。dis[i] 再加上一个负数是小于dis[i]的,而算dis[i]时有可能该有j再到i的(这里具体解释一下:按自己理解,把扩展i,j之前所有的顶点看成a,若a到i权值为10,a到j权值为20,i到j权值为-100,那么接下来a必定要先到i得到dis[i],这之后dis[i]就不能再更改了,然后再由{a,i}到j,但这时会发现:如果由a到j再到i,那么dis[i]会更小,所以这里就出现了错误。再所以,就不能有负权值啊)。

那如果有负权值,怎么搞呢?

可以用    Bellman-Ford算法。


如何保存路径呢?

倒过来想就好了,比如:从源点a经过很多很多步到达了b,然后经过一步到达了终点c,那么此时我们反着想,倒着走,如果满足

dis[b]+Cost[b][c])==dis[c]这个条件,就说明b必然在路径中。。。。

看代码比较清楚点。。。。

#include <cstdio>
#include <iostream>
#define BIG 5
#include <cstring>
#define MIN(a,b) ((a)<(b)?(a):(b))
#define N 6
#define INF 1000005
using namespace std;int q[N+1],dis[N+1],vis[N+1],a,b,cnt;
int Cost[N+1][N+1]=
{{0,0,0,0,0,0},{0,0,20,15,INF,INF,INF},{0,2,0,INF,INF,10,30},{0,INF,4,0,INF,INF,10},{0,INF,INF,INF,0,INF,INF},{0,INF,INF,INF,15,0,INF},{0,INF,INF,INF,4,10,0}
};
//int sp[10];
int index = 0;
void dijstra(int u)
{memset(vis,0,sizeof(vis));for (int i=0; i<=N; i++)dis[i]=INF;dis[u]=0;vis[u] =0;for (int i=1; i<N; i++){int _MIN=INF;for (int j=1; j<=N; j++)if (!vis[j] && dis[j]<_MIN){_MIN=dis[j];u=j;}vis[u]=1;for (int j=1; j<=N; j++)if (!vis[j] && dis[j]>dis[u]+Cost[u][j])dis[j]=dis[u]+Cost[u][j];}
}void Getpath(int u)
{q[++cnt]=u;if (u==a){for (int i=cnt; i>1; i--){cout<<q[i]<<"->";// sp[index++] = q[i];}cout<<q[1]<<endl;cnt--;return ;}for (int i=1; i<=N; i++)if (i!=u  && dis[i] < INF && (dis[i]+Cost[i][u])==dis[u]){Getpath(i);}cnt--;
}int main()
{printf("输入起点和终点:\n");while (scanf("%d%d",&a,&b)!=EOF){//sp[1] = a;cnt=0;if(a == b){printf("0\n");continue ;}dijstra(a);if(dis[b] >= INF){printf("无路可走~\n");continue;}Getpath(b);}return 0;
}







http://www.ppmy.cn/news/163479.html

相关文章

intel Xeon(R) CPU E5-2650 v2 性能测试报告

intel Xeon(R) CPU E5-2650 v2 性能测试报告 一.测试背景: 验证Xeon(R) CPU E5-2650 v2 的性能,和基于KVM的openstack平台的处理能力和稳定性。镜像、虚拟机用horizon控制台管理,按照测试方法从horizon开启虚拟机,…

HDU-2680,Choose the best route(Dijkstra)

Problem Description&#xff1a; One day , Kiki wants to visit one of her friends. As she is liable to carsickness , she wants to arrive at her friend’s home as soon as possible . Now give you a map of the city’s traffic route, and the stations which are …

微软CVE-2023-28252漏洞

微软内核提权0day漏洞 4月12号&#xff0c;微软发布了最新的漏洞补丁程序&#xff0c;此次公告中的内核提权漏洞CVE-2023-28252&#xff0c;由安恒信息、卡巴斯基及Mandiant公司同时捕获&#xff0c;这也是安恒信息成功捕获的第4枚在野内核提权0day&#xff01; 据卫兵实验室…

服务器型号E52680,e5 2680v3 云服务器

e5 2680v3 云服务器 内容精选 换一换 将云服务器加入云服务器组。添加成功后&#xff0c;该云服务器与云服务器组中的其他成员尽量分散地创建在不同主机上。仅支持添加虚拟化类型为KVM的弹性云服务器。当前只支持反亲和性策略&#xff0c;即同一云服务器组中的弹性云服务器分散…

百练_2680:化验诊断

描述 下表是进行血常规检验的正常值参考范围&#xff0c;及化验值异常的临床意义&#xff1a; 给定一张化验单&#xff0c;判断其所有指标是否正常&#xff0c;如果不正常&#xff0c;统计有几项不正常。化验单上的值必须严格落在正常参考值范围内&#xff0c;才算是正常。正常…

前端开发 统一代码风格

在前端开发中&#xff0c;我们通常需要保证代码风格的一致性&#xff0c;而 husky 是一个可以帮助我们在 Git 提交时运行指定脚本的工具&#xff0c;由此我们可以通过 husky 来自动运行代码格式化工具&#xff0c;保证代码风格的统一。 下面是使用 husky 实现前端代码提交格式…

Hdu-2680 Choose the best route

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2680 题目大意&#xff1a; 给你一个有向图&#xff0c;一个起点集合&#xff0c;一个终点&#xff0c;求最短路。。。。 解题思路&#xff1a; 1.自己多加一个超级源点&#xff0c;把起点集合连接到超级源…

20核服务器项目,详细解答E5-2680v2,20核40线程服务器的具体用途怎么体现出来

由我锐讯网络李明辉给你详细解答E5-2680v2&#xff0c;20核40线程服务器的具体用途怎么体现出来. E5-2680v2 20核40线程服务器 一&#xff0e;配置: CPU: E5-2680v2*2 20核40线程 主频: 2.80 GHz,睿频: 3.60 GHz 20核心40线程 内存: 32G(默认配置) 最大128G 硬盘:SATA 1T(…