链接
题目描述
有一个邮递员要送东西,邮局在节点 1。他总共要送 n−1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1 样东西并且最终回到邮局最少需要的时间。
输入格式
第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。
第二行到第 (m+1) 行,每行三个整数,u,v,w,表示从 u 到 v 有一条通过时间为 w 的道 路。
输出格式
输出仅一行,包含一个整数,为最少需要的时间。
输入输出样例
输入 #1
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
说明/提示
对于 30% 的数据,1≤n≤200。
对于 100% 的数据,1≤n≤103
1≤m≤105, 1≤u,v≤n, 1≤w≤104
输入保证任意两点都能互相到达。
思路:咋一看,还以为要用Floyd,但是n告诉你,Floyd肯定超时,所以我们选择使用dijkstra堆优化算法,分析一下,快递员从第二个结点到n个结点,只需要dijkstra一次,然后把所有的dist加起来即可,但是从2~n个结点回来,可不是一对多,是多对一,按照常规的思路,我们需要dji n-1次,然后把所有的dist[1]加起来,我试了一下,会超时,因此我们可以换个思路,建一个反向图如下图所示(2n个结点到结点1的距离等于反图中结点1到结点2n的距离)。这么一来我们只需要dji俩次即可,大大降低了时间复杂度。
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 2e3 + 100;
const int MAX = 1e8;
struct node{
int to;
int next;
int weight;
}edge[100 * maxn];
int head[maxn];
int dist[maxn];
int cnt = 0;
bool vis[maxn];
int n, m;//n个点,m条边
void init()
{
for(int i = 1; i <= n << 1; i++){//n个点
dist[i] = MAX;
vis[i] = false;
}
}
void add(int u, int v, int cost)
{
edge[cnt].weight = cost;
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
struct base{
int point;
int dist;
bool operator < (const base&others)const{
return dist > others.dist;
}
};
void dijkstra(int s)
{
priority_queue<base>q;
dist[s] = 0;
q.push((base){s, 0});
while(!q.empty()){
base current = q.top();
q.pop();
int u = current.point;
int d = current.dist;
if(vis[u])
continue;
else
vis[u] = true;
for(int i = head[u]; ~i; i = edge[i].next){
int v = edge[i].to;
int w = edge[i].weight;
if(!vis[v] && dist[u] + w < dist[v]){
dist[v] = dist[u] + w;
q.push((base){v, dist[v]});
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
init();
fill(head + 1, head + 1 + n, -1);
while(m--){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(n + v, n + u, w);//[1+n, 2n]存放反向图
}
dijkstra(1);
int sum = 0;
for(int i = 2; i <= n; i++){
sum += dist[i];
}
init();
dijkstra(1 + n);
for(int i = 1 + n; i <= n << 1; i++){
sum += dist[i];
}
printf("%d\n", sum);
return 0;
}