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复制

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

【两种方法】

【SPFA】

SPFA

【注意注意】

这是单向路单向路单向路!!!

重要的事情说三遍!!!

(题目中没点出这点但是我的全WA经历让我深刻的认识到了这一点)

【思路】

去和来这是两个完全相反的东西

SPFA跑一个方向是很轻松的

然后另一个方向就很难办了

该怎么办呢?

n遍SPFA?

不太可能这就是一道黄题

对了!可以反向建图!

将方向反过来建出来的图就是完全相反的

某个点到x的距离恰好就是回家的最短距离

这样和正向建图一结合

就能求出去和回的最短路径了

然后求和就可以了

【完整代码】

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. #include<cstring>
  5. using namespace std;
  6. const int Max = 100005;
  7. struct node
  8. {
  9. int y;
  10. int ne;
  11. int z;
  12. }a1[Max << 1],a2[Max << 1];
  13. int n,m,x;
  14. const int M = 1002;
  15. int head1[M],head2[M];
  16. int sum = 0;
  17. void add1(int x,int y,int z)
  18. {
  19. a1[++ sum].y = y;
  20. a1[sum].z = z;
  21. a1[sum].ne = head1[x];
  22. head1[x] = sum;
  23. }
  24. void add2(int x,int y,int z)
  25. {
  26. a2[++ sum].y = y;
  27. a2[sum].z = z;
  28. a2[sum].ne = head2[x];
  29. head2[x] = sum;
  30. }
  31. int d1[M],d2[M];
  32. bool use[M];
  33. void SPFA1()
  34. {
  35. memset(use,false,sizeof(use));
  36. queue<int>q;
  37. for(register int i = 1;i <= n;++ i)
  38. d1[i] = 999999;
  39. d1[x] = 0;
  40. q.push(x);
  41. while(!q.empty())
  42. {
  43. int qwq = q.front();
  44. q.pop();use[qwq] = false;
  45. for(register int i = head1[qwq];i != 0;i = a1[i].ne)
  46. {
  47. int awa = a1[i].y;
  48. if(d1[awa] > d1[qwq] + a1[i].z)
  49. {
  50. d1[awa] = d1[qwq] + a1[i].z;
  51. if(use[awa] == false)
  52. {
  53. use[awa] = true;
  54. q.push(awa);
  55. }
  56. }
  57. }
  58. }
  59. }
  60. void SPFA2()
  61. {
  62. memset(use,false,sizeof(use));
  63. queue<int>q;
  64. for(register int i = 1;i <= n;++ i)
  65. d2[i] = 999999;
  66. d2[x] = 0;
  67. q.push(x);
  68. while(!q.empty())
  69. {
  70. int qwq = q.front();
  71. q.pop();use[qwq] = false;
  72. for(register int i = head2[qwq];i != 0;i = a2[i].ne)
  73. {
  74. int awa = a2[i].y;
  75. if(d2[awa] > d2[qwq] + a2[i].z)
  76. {
  77. d2[awa] = d2[qwq] + a2[i].z;
  78. if(use[awa] == false)
  79. {
  80. use[awa] = true;
  81. q.push(awa);
  82. }
  83. }
  84. }
  85. }
  86. }
  87. int main()
  88. {
  89. scanf("%d%d",&n,&m);
  90. x = 1;
  91. int xx,yy,zz;
  92. for(register int i = 1;i <= m;++ i)
  93. {
  94. scanf("%d%d%d",&xx,&yy,&zz);
  95. add1(xx,yy,zz);
  96. add2(yy,xx,zz);
  97. }
  98. SPFA1();
  99. SPFA2();
  100. int MM = 0;
  101. for(register int i = 1;i <= n;++ i)
  102. MM = MM + d1[i] + d2[i];
  103. cout << MM << endl;
  104. return 0;
  105. }

【dijkstra】

dijkstra + 堆优化

【说在前面的话】

通过这道题发现我真是个可爱的孩子

用dijkstra做的时候

开开心心打一个反向建图

轻轻松松提交上去

然后拿了70分……

堆优化之后的复杂度是O((N+M)logN)完全不会超时

然后我就开始思考各种可能出现的玄学问题

最后焦灼了一个小时

终于发现是数组开小了……

鬼知道为什么数组开小会超时……

【核心思路】

有去有回

如果只是去的话单源最短路径就可以轻轻松松解决掉

但是来回的话

首先想到的是多源最短路径

但是好像跑不过去

这就用到了和上面SPFA一样的思路了

就是反向建图

这样只需要两遍dijkstra就可以解决掉

最后再求个和就没有问题了

【完整代码】

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. using namespace std;
  5. const int Max = 100004;
  6. const int M = 1003;
  7. struct point
  8. {
  9. int w;
  10. int x;
  11. bool operator < (const point & xx)const
  12. {
  13. return xx.w < w;
  14. }
  15. };
  16. int n,m;
  17. struct node
  18. {
  19. int y,ne;
  20. int z;
  21. }a1[Max << 1],a2[Max << 1];
  22. int sum1 = 0,sum2 = 0;
  23. int head1[M],head2[M];
  24. inline int read()
  25. {
  26. int x=0; char ch=getchar();
  27. while (ch<'0' || ch>'9') ch=getchar();
  28. while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
  29. return x;
  30. }
  31. void add1(int x,int y,int z)
  32. {
  33. a1[++ sum1].y = y;
  34. a1[sum1].z = z;
  35. a1[sum1].ne = head1[x];
  36. head1[x] = sum1;
  37. }
  38. void add2(int x,int y,int z)
  39. {
  40. a2[++ sum2].y = y;
  41. a2[sum2].z = z;
  42. a2[sum2].ne = head2[x];
  43. head2[x] = sum2;
  44. }
  45. int dis1[M],dis2[M];
  46. bool use1[M],use2[M];
  47. priority_queue<point>q;
  48. void dj1()
  49. {
  50. for(register int i = 2;i <= n;++ i)
  51. dis1[i] = 999999;
  52. dis1[1] = 0;
  53. q.push((point){0,1});
  54. while(!q.empty())
  55. {
  56. point qwq = q.top();
  57. q.pop();
  58. int x = qwq.x;
  59. if(use1[x] == true)
  60. continue;
  61. use1[x] = true;
  62. for(register int i = head1[x];i != 0;i = a1[i].ne)
  63. {
  64. int awa = a1[i].y;
  65. if(dis1[awa] > dis1[x] + a1[i].z)
  66. {
  67. dis1[awa] = dis1[x] + a1[i].z;
  68. if(use1[awa] == false)
  69. q.push((point){dis1[awa],awa});
  70. }
  71. }
  72. }
  73. }
  74. void dj2()
  75. {
  76. for(register int i = 2;i <= n;++ i)
  77. dis2[i] = 999999;
  78. dis2[1] = 0;
  79. q.push((point){0,1});
  80. while(!q.empty())
  81. {
  82. point qwq = q.top();
  83. q.pop();
  84. int x = qwq.x;
  85. if(use2[x] == true)
  86. continue;
  87. use2[x] = true;
  88. for(register int i = head2[x];i != 0;i = a2[i].ne)
  89. {
  90. int awa = a2[i].y;
  91. if(dis2[awa] > dis2[x] + a2[i].z)
  92. {
  93. dis2[awa] = dis2[x] + a2[i].z;
  94. if(use2[awa] == false)
  95. q.push((point){dis2[awa],awa});
  96. }
  97. }
  98. }
  99. }
  100. int main()
  101. {
  102. n = read();m = read();
  103. int x,y,z;
  104. for(register int i = 1;i <= m;++ i)
  105. {
  106. x = read();y = read();z = read();
  107. add1(x,y,z);add2(y,x,z);
  108. }
  109. dj1();
  110. dj2();
  111. int ans = 0;
  112. for(register int i = 2;i <= n;++ i)
  113. ans += dis1[i] + dis2[i];
  114. cout << ans << endl;
  115. return 0;
  116. }

洛谷 P1629 邮递员送信 题解的更多相关文章

  1. yzoj P1412 & 洛谷P1629 邮递员送信 题解

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

  2. 洛谷 P1629 邮递员送信-反向建边

    洛谷 P1629 邮递员送信 题目描述: 有一个邮递员要送东西,邮局在节点 11.他总共要送 n-1n−1 样东西,其目的地分别是节点 22 到节点 nn.由于这个城市的交通比较繁忙,因此所有的道路都 ...

  3. 洛谷——P1629 邮递员送信

    P1629 邮递员送信 题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要 ...

  4. 洛谷P1629 邮递员送信

    题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间.这个邮递员每 ...

  5. 洛谷 P1629 邮递员送信

    题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有M条道路,通过每条道路需要一定的时间.这个邮递员每 ...

  6. 洛谷—— P1629 邮递员送信

    https://www.luogu.org/problem/show?pid=1629 题目描述 有一个邮递员要送东西,邮局在节点1.他总共要送N-1样东西,其目的地分别是2~N.由于这个城市的交通比 ...

  7. 洛谷P1629 邮递员送信 最短路-Djistra

    先上一波题目qwq https://www.luogu.org/problem/P1629· 复习了一波 dijstra 的 priority_queue(优先队列)优化的写法 tips: 求单项路中 ...

  8. 洛谷P2832 行路难 分析+题解代码【玄学最短路】

    洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...

  9. 【洛谷P3960】列队题解

    [洛谷P3960]列队题解 题目链接 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia 所在的方阵中有 n×m ...

随机推荐

  1. 《JAVA高并发编程详解》-七种单例模式

  2. ArcGIS Engine中C#开发不能引用ESRI.ArcGIS.AxControls问题

    问题:ArcGIS Engine中C#开发不能引用ESRI.ArcGIS.AxControls问题 解决方法:将这里的特定版本改成“False”即可.

  3. vs配置opencv(只需一次)

    一.配置环境变量(bin) 二.配置属性表 1.配置包含(include)目录 2.配置库(lib)目录 3.配置依赖项(.lib)

  4. ubuntu16.04 打开chrome弹出“Enter password to unlock your login keyring”解决方法

    问题如图 输入开机密码发现验证失败. 解决 命令: find ~/ -name login.keyring 查找相关文件. 命令: sudo rm -rf /home/la/.local/share/ ...

  5. sqlserver 2005 数据库的差异备份与还原

    找到一个可靠的步骤,点开链接:http://blog.csdn.net/kevindr/article/details/22154323

  6. 2019 网宿科技java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.网宿科技等公司offer,岗位是Java后端开发,最终选择去了网宿科技. 面试了很多家公司,感觉大部分公司考察的点 ...

  7. 获取本机的IP地址和mac地址

    1. 以前一直用ipconfig来查看ip地址,哈哈哈,现在发现挺好玩 #获取本机的IP地址和mac地址 import uuid import socket def get_mac_address() ...

  8. Java自学-控制流程 continue

    Java的 continue语句 继续下一次循环 示例 1 : continue 如果是双数,后面的代码不执行,直接进行下一次循环 public class HelloWorld { public s ...

  9. webpack集成vue单文件模式的很多坑(研究了1个星期)

    1.一开始不知道局部安装webpack后,如何调用webpack. 后来看说明文档(webpack中文网)才知道,有个npx可以启动本地安装的webpack. 我估计:全局安装webpack,全局的w ...

  10. 结对编程(-java实现)

    一 .Github项目地址:https://github.com/mushan520/Four-fundamental-rules-java.git                           ...