谁时拯救这个世界的英雄?在二次元世界中,两个最有爱的反派角色,莫过于火箭队的这两员了。他们为了维护这个宇宙的和平而存在,尽管每次确实有失利了,但是,却给我们留下了深刻的印象。那么,在三次元世界中,谁是拯救这个世界的英雄呢?我认为,此人乃是阿桑奇。
好了,这里不说到底是谁在拯救这个世界了,不过,这一弹确实和火箭队有关。
如图所示,在云雾缭绕的氛围中有若干个黑色的地洞,而位于地洞P的那个房间坐着的人,就是板木老人了。我们这里以N点作为起始点,每进入一个地洞,则会有一种对应的转移(当然,这种转移可以是双向的,对应为无向图),我们的目的是到达P点,当然,我们可以尝试很多方式,也愿意避免碰到火箭队的内部队员的挑战。我们如何可以方便地到达P点呢?(这里的方便指明了两点,第一,转移的次数可以尽可能少,第二,尽量可以避免遇到前来挑战的人),明确了这两点之后,改问题转化为了一个带权重(widget的值应该就是挑战者的能力了)的最短路问题了。
这又是一个火箭队的秘密基地,不过,这里的情况貌似比之前的要简单许多,多了几道门,少了几个状态转移区域。我们可以采用同样的方式,来利用AI,用最短的转移次数到达我们所需要到达的目标点。我们将每一个“转移区域”按照序号分别标注,因为挑战者的干扰,这里对每一条边考虑一个权重(这里的权重是正值,因为,即使是没有火箭队的内部人员存在,我们的权重也是大于等于1的(这一步算你转移耗费的能量,然后,以此作为衡量标准来衡量那些脑残的火箭队挑战者的权重)),考虑到权重的恒正,我们可以利用Dijkstra算法来计算最短路径了!
Dijkstra奥义:
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。
步骤如下:
STEP 1: 初使时令 S={V0},T={其余顶点},T中顶点对应的距离值若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值若不存在<V0,Vi>,d(V0,Vi)为∝
STEP 2: 从T中选取一个其距离值为最小的顶点W且不在S中,加入S
STEP 3: 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的距离值缩短,则修改此距离值重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
Input:每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有转移区域的数目和转移的路径(这里的边是给定的)。接下来是M行转移路径信息。每一行有三个整数A,B,X,表示转移区域A和转移区域B之间的“权重”(这个概念在之前已经解释过了)。再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。
Output:计算耗费能量的最小值,如果不能到达的话,输出-1。
Solve:
这里的时间复杂度是O(N^2),还可以利用比较好的数据结构将该算法进行进一步的优化,Dijkstra算法最好的复杂度也是O(NlogN+E),用Fibonacci堆来实现优先队列就可以达到该复杂度。
2
3 #include <iostream>
4
5 #include <cstdio>
6
7 using namespace std;
8
9
10
11 #define Max 210
12
13
14
15 // 设置一个极大的常数,INTMAX,由于INT本身是32位的,所以,这个INTMAX已经非常大了
16
17 const int INTMAX= 1<< 30;
18
19 int p[Max][Max];
20
21 int dist[Max],s[Max];
22
23 int n,m,v;
24
25
26
27 // 在初始化的时候,将所有的边设为最大值
28
29 void init()
30
31 {
32
33 for ( int i= 0;i<n;i++)
34
35 for ( int j= 0;j<n;j++)
36
37 p[i][j]=INTMAX;
38
39 }
40
41
42
43 void dijkstra()
44
45 {
46
47 int i,w,j,min,u;
48
49 for (i= 0;i<n;i++)
50
51 {
52
53 // 这里说明起始点到每一条边的距离
54
55 dist[i]=p[v][i];
56
57 s[i]= 0;
58
59 }
60
61 s[v]= 1;
62
63 // 自己到自己是没有长度的
64
65 dist[v]= 0;
66
67 for (i= 0;i<n;i++)
68
69 {
70
71 min=INTMAX;
72
73 u=v;
74
75 // 找到到某一点(最开始是起始点)的最短路径
76
77 for (j= 0;j<n;j++)
78
79 if (!s[j]&&dist[j]<min)
80
81 min=dist[u=j];
82
83 s[u]= 1;
84
85 // 找到一条可以代替的最短路
86
87 for (w= 0;w<n;w++)
88
89 if (!s[w]&&dist[u]+p[u][w]<dist[w]&&p[u][w]<INTMAX)
90
91 dist[w]=dist[u]+p[u][w];
92
93 }
94
95 }
96
97
98
99 int main()
100
101 {
102
103 int i,j,a,b,c,k;
104
105 // 开始,先输入起点和对应的边
106
107 while (cin>>n>>m)
108
109 {
110
111 // 初始化各条边
112
113 init();
114
115 for (i= 0;i<m;i++)
116
117 {
118
119 scanf( " %d%d%d ",&a,&b,&c);
120
121 // 这里注意到边是双向的,我们既可以转移过去,也可以转移回来
122
123 if (c<p[a][b])
124
125 p[a][b]=p[b][a]=c;
126
127 }
128
129 // 这里输入起始点和终止点
130
131 cin>>v>>k;
132
133 dijkstra();
134
135 // 这里说明路径找不到
136
137 if (dist[k]==INTMAX) cout<< " -1 "<<endl;
138
139 else cout<<dist[k]<<endl;
140
141 }
142
143 return 0;
144
145 }