HDU 2680 最短路 迪杰斯特拉算法 添加超级源点
Choose the best route
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5273 Accepted Submission(s): 1680
Each case begins with three integers n, m and s,(n<1000,m<20000,1=<s<=n) n stands for the number of bus stations in this city and m stands for the number of directed ways between bus stations .(Maybe there are several ways between two bus stations .) s stands for the bus station that near Kiki’s friend’s home.
Then follow m lines ,each line contains three integers p , q , t (0<t<=1000). means from station p to station q there is a way and it will costs t minutes .
Then a line with an integer w(0<w<n), means the number of stations Kiki can take at the beginning. Then follows w integers stands for these stations.
虽然又是迪杰斯特拉算法,但是还是搬到博客上来写,是因为解题思想挺牛的。
节点为10^3,本来用迪杰斯特拉,就算没优化,也是没什么问题的,可是题目指定了终点,又给定了一系列点作为起点,我估摸着,即使代码中间优化剪枝,如果数据够强力,还是有TLE危险。(后来即使用n^2算法也跑了400+ms,所以如果按这个思路几乎是TLE的命)。
后来大神博客介绍了两种思路。。瞬间就把时间复杂度降低了。。简直碉堡了
思路1、添加超级源点。这也是我之后选择的方法
即定义一个0号点,d[0]=0,并且v[0][j]=0,j为题目指定的一系列初始点坐标,使得将那一系列起始点都统一成了一个超级源点,但是因为把v[0][j]都设置为0,所以不会对结果产生任何影响,这样,只要照着朴素的迪杰斯特拉算法敲一遍,遍历n+1个点,即可得到结果。
思路2.逆向图
因为题目不是指定了最终点只是一个点吗?何不逆向从终点出发,这样,只是把循环反转了一下,照样是朴素的迪杰斯特拉算法。。最后比较一下,出发的那一系列点的数值即可。
我用的是思路一,思路二我大概想了一下,不会太难写,除了逆向的时候注意一下细节。。对了,必须提醒一下!!!该题目的图为单向图!!!多向图就会完蛋!!!!,HDU的discuss里面说是因为英语不好,但是我仔细再读了一下,也没发现哪里说了是单向的。。而且尼玛,我严重怀疑出题者是不是自己忘了弄双向,根据生活经验,尼玛哪个城市的公交是只去不回的!!!!。。。还有必须吐槽一下今天做的其他几个最短路的题目,还都是HDU的,都尼玛是坑货题意,明明两点存在多条路径,需要在读入的时候,判断一下,。。但题目愣是一点都没说。。幸好有discuss里面早就被坑死的人提示了这里,否则我还不知道要WA多少次。。。
好了 不废话了、、、
#include <iostream> #include <cstdio> #include <cstring> #define inf 100000000 using namespace std; int d[1005]; int vis[1005]; int v[1005][1005]; int n,m,s; int stapoint[1005]; int w; int dijst() { int i,j,k; memset(vis,0,sizeof vis); d[0]=0;//设置超级源点 for (i=1; i<=w; i++) { v[0][stapoint[i]]=0; //将超级源点与已知一系列初始点的路程设置为0; } for (j=0; j<=n; j++) { int mini=inf; int loc=0; for (k=0; k<=n; k++) if (mini>d[k]&&!vis[k]) mini=d[k],loc=k; if (mini==inf) break; vis[loc]=1; for (k=0; k<=n; k++) { if (d[k]>d[loc]+v[loc][k]) d[k]=d[loc]+v[loc][k]; //cout<<k<<" "<<d[k]<<endl; } } if (d[s] < inf) return d[s]; else return -1; } int main() { while (scanf("%d %d %d",&n,&m,&s)!=EOF) { int i,j,k; for (i=0; i<=n; i++) { d[i]=inf; for (j=0; j<=n; j++) v[i][j]=inf; } for (i=1; i<=m; i++) { int a,b,c; scanf("%d %d %d",&a,&b,&c); if (v[a][b]>c) v[a][b]=c; //cout<<v[a][b]<<endl; } scanf("%d",&w); for (i=1; i<=w; i++) scanf("%d",&stapoint[i]); printf("%d\n",dijst()); } return 0; }