邮 递 员 送 信 邮递员送信 邮递员送信
L u o g u P 1629 Luogu\ P1629 Luogu P1629
题目描述
有一个邮递员要送东西,邮局在节点 11。他总共要送 n-1n−1 样东西,其目的地分别是节点 22 到节点 nn。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 mm 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1n−1 样东西并且最终回到邮局最少需要的时间。
输入格式
第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。
第二行到第 (m+1)(m+1) 行,每行三个整数,u , v , w,表示从 u 到 v 有一条通过时间为 w 的道路。
输出格式
输出仅一行,包含一个整数,为最少需要的时间。
输入输出样例
输入样例
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
输出样例
83
说明/提示
对于 30% 的数据,1≤n≤200
对于 100% 的数据,1≤n≤10^3 ,1≤m≤10^5,输入保证任意两点都能互相到达。
解题思路
- 由题可知,可以理解为你需要从起点到所有点,然后再从所有点到起点
- 所以就可以让这两次的和最小,就可以正常跑一次SPFA,然后再把所有边反过来再跑一边SPFA即可
代码如下
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,p,u,v,w,ans,t[1001],tt[1001],k,d[1001],dd[1001];
struct node
{
int to,next,x;//to表示这个儿子是谁 next表示下一个儿子的位置 x表示父亲到当前儿子的边的距离(值)
}e1[100001],e2[100001];
queue<int>q;
bool in[1001];
int main()
{
memset(d, 0x7f, sizeof(d));
memset(dd, 0x7f, sizeof(dd));
scanf("%d%d",&n,&m);
p = 1;
for(int i = 1;i <= m;++i)
{
scanf("%d%d%d",&u,&v,&w);
e1[++k] = (node){v, t[u], w};
t[u] = k;
e2[k] = (node){u, tt[v], w};
tt[v] = k;
}
q.push(p);//起点插入队列
in[p] = 1;//记录到过这个点
d[p] = 0;//距离
while(!q.empty())//还有下一个点可以走
{
int now = q.front();//现在在那个点
q.pop();//把这个点弹出去
for (int i = t[now]; i; i = e1[i].next)//枚举它所有到的点
{
int y = e1[i].to;//到它的下一个点
if (d[now] + e1[i].x < d[y])//判断哪个距离短
{
d[y] = d[now] + e1[i].x;//如果更短,就更新值
if (!in[y])//如果没有到过这个点(避免死循环)
{
in[y] = 1;//标记它走过
q.push(y);//插入点继续走
}
}
}
in[now] = 0;//把不在路径上的点的标记清除
}
q.push(p);
in[p] = 1;
dd[p] = 0;
while(!q.empty()) //如上所示反过来即可
{
int now = q.front();
q.pop();
for (int i = tt[now]; i; i = e2[i].next)
{
int y = e2[i].to;
if (dd[now] + e2[i].x < dd[y])
{
dd[y] = dd[now] + e2[i].x;
if (!in[y])
{
in[y] = 1;
q.push(y);
}
}
}
in[now] = 0;
}
for(int i = 1;i <= n; ++i)
if(i != p) ans += d[i] + dd[i];
printf("%d",ans);
return 0;
}
本文探讨了一个邮递员如何在繁忙的城市交通中,寻找最优路径以最短时间完成送信任务并返回邮局的问题。通过两次运行SPFA算法,分别计算从邮局到各节点及反方向的最短路径,进而找到总时间最小的方案。
1011

被折叠的 条评论
为什么被折叠?



