洛谷P1629《邮递员送信》

一个正向图,一个反向图

题目描述

有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间。这个邮递员每次只能带一样东西。求送完这N-1样东西并且最终回到邮局最少需要多少时间。

输入输出格式

输入格式

第一行包括两个整数N和M。

第2到第M+1行,每行三个数字U、V、W,表示从A到B有一条需要W时间的道路。 满足1<=U,V<=N,1<=W<=10000,输入保证任意两点都能互相到达。

【数据规模】

对于30%的数据,有1≤N≤200;

对于100%的数据,有1≤N≤1000,1≤M≤100000。

输出格式

输出仅一行,包含一个整数,为最少需要的时间。

输入输出样例

输入样例

1
2
3
4
5
6
7
8
9
10
11
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2

输出样例

1
83

解题思路

类似题目:洛谷P1821《[USACO07FEB]银牛派对Sliver Cow Party》
题解:洛谷P1821 《[USACO07FEB]银牛派对Silver Cow Party》

对于这类题目,我们考虑建一个反向(所有边的方向都相反)的图。

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
struct Graph {
static const int MAXN = 1000 + 10;
static const int MAXM = 100000 + 10;

struct Node {
int nweight, now;

Node() { nweight = now = 0; }

bool operator < (const Node &that) const {
return nweight > that.nweight;
}
};

struct Edge {
int now, weight, next;
} edge[MAXM * 2];

int head[MAXN], dis[MAXN], cnt;

inline void addEdge(int prev, int next, int weight) {
edge[++cnt].now = next;
edge[cnt].weight = weight;
edge[cnt].next = head[prev];
head[prev] = cnt;
}

inline Node NewNode(int nowWeight, int now) {
Node tmp;
tmp.nweight = nowWeight;
tmp.now = now;
return tmp;
}

inline void SPFA() {
// 最短路
// 一块写进去更方便
memset(dis, 0x7f, sizeof(dis));
std::priority_queue<Node> q;
q.push(NewNode(0, 1));
dis[1] = 0;
while (!q.empty()) {
Node NowNode = q.top();
q.pop();
int now = NowNode.now;
for (int e = head[now]; e; e = edge[e].next) {
int to = edge[e].now;
if (dis[to] > dis[now] + edge[e].weight) {
dis[to] = dis[now] + edge[e].weight;
q.push(NewNode(dis[to], to));
}
}
}
}
};

这里我选择一个稍微懒一点的方法,将图存到一个结构体里面,创建的时候只要 Graph g1, g2; 即可。

最后答案即为

\sum_{i = 1}^{n} \text{g1.dis}[i] + \text{g2.dis}[i]

代码实现

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* -- Basic Headers -- */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>

/* -- STL Iterators -- */
#include <vector>
#include <string>
#include <stack>
#include <queue>

/* -- External Headers -- */
#include <map>
#include <cmath>

/* -- Defined Functions -- */
#define For(a,x,y) for (int a = x; a <= y; ++a)
#define Forw(a,x,y) for (int a = x; a < y; ++a)
#define Bak(a,y,x) for (int a = y; a >= x; --a)

namespace FastIO {

inline int getint() {
int s = 0, x = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') x = -1;
ch = getchar();
}
while (isdigit(ch)) {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * x;
}
inline void __basic_putint(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x >= 10) __basic_putint(x / 10);
putchar(x % 10 + '0');
}

inline void putint(int x, char external) {
__basic_putint(x);
putchar(external);
}
}


namespace Solution {
struct Graph {
static const int MAXN = 1000 + 10;
static const int MAXM = 100000 + 10;

struct Node {
int nweight, now;

Node() { nweight = now = 0; }

bool operator < (const Node &that) const {
return nweight > that.nweight;
}
};

struct Edge {
int now, weight, next;
} edge[MAXM * 2];

int head[MAXN], dis[MAXN], cnt;

inline void addEdge(int prev, int next, int weight) {
edge[++cnt].now = next;
edge[cnt].weight = weight;
edge[cnt].next = head[prev];
head[prev] = cnt;
}

inline Node NewNode(int nowWeight, int now) {
Node tmp;
tmp.nweight = nowWeight;
tmp.now = now;
return tmp;
}

inline void SPFA() {
memset(dis, 0x7f, sizeof(dis));
std::priority_queue<Node> q;
q.push(NewNode(0, 1));
dis[1] = 0;
while (!q.empty()) {
Node NowNode = q.top();
q.pop();
int now = NowNode.now;
for (int e = head[now]; e; e = edge[e].next) {
int to = edge[e].now;
if (dis[to] > dis[now] + edge[e].weight) {
dis[to] = dis[now] + edge[e].weight;
q.push(NewNode(dis[to], to));
}
}
}
}
} g1, g2;

int n, m;
}

signed main() {
#define HANDWER_FILE
#ifndef HANDWER_FILE
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
using namespace Solution;
using FastIO::getint;
n = getint();
m = getint();
For (i, 1, m) {
int prev = getint();
int next = getint();
int weight = getint();
g1.addEdge(prev, next, weight);
g2.addEdge(next, prev, weight);
}
g1.SPFA();
g2.SPFA();
int ans = 0;
For (i, 1, n) {
ans += g1.dis[i] + g2.dis[i];
}
FastIO::putint(ans, '\n');
return 0;
}