HDU_4725_思维建图+最短路
- 难点是如何将楼层转化到图中,
- 用2个点将一个面(楼层)抽象出来,1个入点,1个出点
- 一个面上的所有点都指向出点,权值为0
- 入点指向该面所有的点(除了出点),权值为0
- 入点指向出点,权值为
0
, - 中间的楼层的出点分别指向上一层的入点和下一层的入点,权值为
c
.将所有楼层都连接起来 - 没有最短路则
dist[n] = MAX
- dij
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;
vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];
int dij() {
priority_queue<pair<int,int> > que;
memset(dist,0x3f,sizeof dist);
que.push( make_pair(0,1) );
dist[1] = 0;
while (!que.empty()) {
int cur = que.top().second; que.pop();
for (int i=0; i<e[cur].size(); i++) {
int to = e[cur][i].first;
int div = e[cur][i].second;
if (dist[to] > dist[cur] + div) {
dist[to] = dist[cur] + div;
que.push( make_pair(-dist[to],to) );
}
}
}
return dist[n];
}
int main() {
// freopen("a.txt","r",stdin);
int times,k=0;
scanf("%d",×);
while (times--) {
scanf("%d%d%d",&n,&m,&cost);
// 楼层抽象化成2个点,一个入点,一个出点
int temp;
for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
scanf("%d",&temp);
e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
}
// 每个点之间的边
int from,to,div;
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&from,&to,&div);
e[from].push_back( make_pair(to,div) );
e[to].push_back( make_pair(from,div));
}
// 当前层的 出点 与 相邻层的 入点 建边
for (int i=1; i<=n; i++) {
from = 2 * i + n; // 出点
if (i > 1) {
to = from - 3;
// 该层的出点,到上一层的入点
e[from].push_back( make_pair(to,cost) );
}
if (i < n) {
to = from + 1;
// 该层的出点,到下一层的入点
e[from].push_back( make_pair(to,cost) );
}
}
int ans = dij();
if (ans == MAX) printf("Case #%d: -1\n",++k);
else printf("Case #%d: %d\n",++k,ans);
// 清除上一组数据
for (int i=1; i<=3 * n; i++) e[i].clear();
}
return 0;
} - spfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83#include <iostream>
#include <string.h>
#include <queue>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 3e5+5;
const int MAX = 0x3f3f3f3f;
vector<pair<int,int> > e[maxn];
int n,m,cost;
int dist[maxn];
bool vis[maxn];
int spfa() {
queue<int> que;
memset(vis,0,sizeof vis);
memset(dist,0x3f,sizeof dist);
que.push(1);
dist[1] = 0; vis[1] = 1;
while (!que.empty()) {
int cur = que.front(); que.pop();
vis[cur] = 0;
for (int i=0; i<e[cur].size(); i++) {
int to = e[cur][i].first;
int div = e[cur][i].second;
if (dist[to] > dist[cur] + div) {
dist[to] = dist[cur] + div;
if (!vis[to]) {
vis[to] = 1;
que.push(to);
}
}
}
}
return dist[n];
}
int main() {
// freopen("a.txt","r",stdin);
int times,k=0;
scanf("%d",×);
while (times--) {
scanf("%d%d%d",&n,&m,&cost);
// 楼层抽象化成2个点,一个入点,一个出点
int temp;
for (int i=1; i<=n; i++) { //i代表点,temp是该点的楼层
scanf("%d",&temp);
e[temp*2+n-1].push_back( make_pair(i,0) ); // 入点指向平面的点
e[i].push_back( make_pair(temp*2+n,0) ); // 平面中的点指向出点
}
// 每个点之间的边
int from,to,div;
for (int i=1; i<=m; i++) {
scanf("%d%d%d",&from,&to,&div);
e[from].push_back( make_pair(to,div) );
e[to].push_back( make_pair(from,div));
}
// 当前层的 出点 与 相邻层的 入点 建边
for (int i=1; i<=n; i++) {
from = 2 * i + n; // 出点
if (i > 1) {
to = from - 3;
// 该层的出点,到上一层的入点
e[from].push_back( make_pair(to,cost) );
}
if (i < n) {
to = from + 1;
// 该层的出点,到下一层的入点
e[from].push_back( make_pair(to,cost) );
}
}
int ans = spfa();
if (ans == MAX) printf("Case #%d: -1\n",++k);
else printf("Case #%d: %d\n",++k,ans);
// 清除上一组数据
for (int i=1; i<=3 * n; i++) e[i].clear();
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!