Description

FGD 想从成都去上海旅游。在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情。经过这些城市的顺序不是完全随意的,比如说 FGD 不希望在刚吃过一顿大餐之后立刻去下一个城市登山,而是希望去另外什么地方喝下午茶。幸运的是,FGD 的旅程不是既定的,他可以在某些旅行方案之间进行选择。由于 FGD 非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够的精力来欣赏风景。整个城市交通网络包含 N 个城市以及城市与城市之间的双向道路 M 条。城市自 1 至 N 依次编号,道路亦然。没有从某个城市直接到它自己的道路,两个城市之间最多只有一条道路直接相连,但可以有多条连接两个城市的路径。任意两条道路如果相遇,则相遇点也必然是这 N 个城市之一,在中途,由于修建了立交桥和下穿隧道,道路是不会相交的。每条道路都有一个固定长度。在中途,FGD 想要经过 K(K<=N-2)个城市。成都编号为 1,上海编号为 N,而 FGD 想要经过的 N 个城市编号依次为 2,3,...,K+1。举例来说,假设交通网络如下图。FGD 想要经过城市 2,3,4,5,并且在 2 停留的时候在 3 之前,而在 4,5 停留的时候在 3 之后。那么最短的旅行方案是1-2-4-3-4-5-8 , 总长度为 19。注意 FGD 为了从城市 2 到城市 4 可以路过城市 3,但不在城市 3 停留。这样就不违反 FGD 的要求了。并且由于 FGD 想要走最短的路径,因此这个方案正是 FGD需要的。

Input

第一行包含 3 个整数 N(2<=N<=20000),M(1<=M<=200000),K(0<=K<=20),意义如上所述。以下 M 行,每行包含 3 个整数 X,Y,Z,(1<=X<y<=n, 1<="Z=1000)表示城市 X与 Y 之间有一条双向道路。你可以认为输入文件使得一定能自成都到上海以及任何 FGD 想要去的城市。"下一行包含一个整数 G(0<=G<=K*(K-1)/2)。以下 G 行,每行包含 2 个整数 X Y,(2<=X,Y<=K+1)表示 FGD 想要在游览城市Y 之前,一定要游览城市 X。你可以认为至少存在一种满足所有限制的游览方案。

Output

只包含一行,包含一个整数,表示最短的旅行距离。

Sample Input

8 15 4

1 2 3

1 3 4

1 4 4

1 6 2

1 7 3

2 3 6

2 4 2

2 5 2

3 4 3

3 6 3

3 8 6

4 5 2

4 8 6

5 7 4

5 8 6

3

2 3

3 4

3 5

Sample Output

19

Hint

下面对应于题目中给出的例子。

Solution

看到k非常小,就可以想到状态压缩的动态规划(先例:售货员的难题)。设f[i][j]表示经过的1到k+1的点的集合为i,当前所在点为j时的最短路径。那么有如下状态转移方程:

\[f[i|(1<<l)][l]=min(f[i][j]+dis[j][l],f[i|(1<<l)][l])
\]

其中dis[j][l]表示从j到l的最短路径,那么为了判断一个点是否满足其先要访问的点的条件,可以用g[i]表示一个点i的所有前驱节点集合(同样用状态压缩),如果在状态转移方程中满足i&g[i]=g[i],就说明可行 。dis数组可以用SPFA跑出来。动态规划完成后,由于没有将第n个点计算在内,所以最终的答案为:

\[ans=max(f[1<<k][i]+dis[i][n])_{i=1,2,...,k+1}
\]

另外,为了表示方便和节省空间,第i个点在二进制集合中的位置可设为i-2,这样就可以从第0位开始表示了。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <queue>
  4. #include <cstring>
  5. #define N 20002
  6. #define M 200002
  7. #define int long long
  8. using namespace std;
  9. int head[N],ver[M*2],nxt[M*2],edge[M*2],l;
  10. int n,m,k,c,i,j,d[22][22],dis[N],f[1048576][22],g[22];
  11. bool in[N];
  12. int read()
  13. {
  14. char c=getchar();
  15. int w=0;
  16. while(c<'0'||c>'9') c=getchar();
  17. while(c<='9'&&c>='0'){
  18. w=w*10+c-'0';
  19. c=getchar();
  20. }
  21. return w;
  22. }
  23. void insert(int x,int y,int z)
  24. {
  25. l++;
  26. ver[l]=y;
  27. edge[l]=z;
  28. nxt[l]=head[x];
  29. head[x]=l;
  30. }
  31. void SPFA(int s)
  32. {
  33. queue<int> q;
  34. memset(in,0,sizeof(in));
  35. memset(dis,0x3f,sizeof(dis));
  36. q.push(s);
  37. in[s]=1;
  38. dis[s]=0;
  39. while(!q.empty()){
  40. int x=q.front();
  41. q.pop();
  42. for(int i=head[x];i;i=nxt[i]){
  43. int y=ver[i];
  44. if(dis[y]>dis[x]+edge[i]){
  45. dis[y]=dis[x]+edge[i];
  46. if(!in[y]){
  47. q.push(y);
  48. in[y]=1;
  49. }
  50. }
  51. }
  52. in[x]=0;
  53. }
  54. for(int i=1;i<=k+1;i++) d[s][i]=dis[i];
  55. d[s][k+2]=dis[n];
  56. }
  57. signed main()
  58. {
  59. freopen("atr.in","r",stdin);
  60. freopen("atr.out","w",stdout);
  61. n=read();m=read();k=read();
  62. for(i=1;i<=m;i++){
  63. int u,v,w;
  64. u=read();v=read();w=read();
  65. insert(u,v,w);
  66. insert(v,u,w);
  67. }
  68. c=read();
  69. for(i=1;i<=c;i++){
  70. int x,y;
  71. x=read();y=read();
  72. g[y]|=(1<<(x-2));
  73. }
  74. for(i=1;i<=k+1;i++) SPFA(i);
  75. memset(f,-1,sizeof(f));
  76. f[0][1]=0;
  77. for(i=0;i<=(1<<k)-1;i++){
  78. for(j=1;j<=k+1;j++){
  79. if(f[i][j]!=-1){
  80. for(l=2;l<=k+1;l++){
  81. if((i&g[l])==g[l]){
  82. if(f[i|(1<<(l-2))][l]==-1) f[i|(1<<(l-2))][l]=f[i][j]+d[j][l];
  83. else f[i|(1<<(l-2))][l]=min(f[i|(1<<(l-2))][l],f[i][j]+d[j][l]);
  84. }
  85. }
  86. }
  87. }
  88. }
  89. int ans=1<<30;
  90. for(i=1;i<=k+1;i++){
  91. if(f[(1<<k)-1][i]!=-1) ans=min(ans,f[(1<<k)-1][i]+d[i][k+2]);
  92. }
  93. cout<<ans<<endl;
  94. fclose(stdin);
  95. fclose(stdout);
  96. return 0;
  97. }

Test 3.27 T2 旅行的更多相关文章

  1. 【NOIP2016练习】T2 旅行(树形DP,换根)

    题意:小C上周末和他可爱的同学小A一起去X湖玩. X湖景区一共有n个景点,这些景点由n-1条观光道连接着,从每个景点开始都可以通过观光道直接或间接地走到其他所有的景点.小C带着小A从1号景点开始游玩. ...

  2. NOIP模拟17.9.22

    NOIP模拟17.9.22 前进![问题描述]数轴的原点上有一只青蛙.青蛙要跳到数轴上≥

  3. python中的thread

    转载自: http://blog.sina.com.cn/s/blog_9f488855010198vn.html 正确与否未验证 python中得thread的一些机制和C/C++不同:在C/C++ ...

  4. 【JDK源码分析】String的存储区与不可变性

    // ... literals are interned by the compiler // and thus refer to the same object String s1 = " ...

  5. java多线程系类:基础篇:04synchronized关键字

    概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...

  6. 二模01day1解题报告

    T1.音量调节(changingsounds) 有n个物品的背包(有点不一样,每个物品必须取),给出初始价值,物品价值可正可负(就是两种选择嘛),求可能的最大价值,不可能(<0或>maxs ...

  7. C# 线程间互相通信

    C#线程间互相通信主要用到两个类:AutoResetEvent和ManualResetEvent. 一.AutoResetEvent AutoResetEvent 允许线程通过发信号互相通信,线程通过 ...

  8. Linux 常用命令解析和Bash Shell使用示例脚本演示

     摘要 Linux命令是基于文本格式输入输出的一种程序,依照Unix哲学中强调的程序功能简单,输入宽松,输出严谨,各种程序组合能够具有更强大的功能,而具有这样的灵活性的主要原因是Linux规定程序 ...

  9. JAVA编程思想(2) - 操作符(一)

    "在最底层,Java中的数据是通过操作符来操作的." 1. 使用Java操作符 -操作符接受一个或者多个參数,并生成一个新值,參数的形式与普通的方法调用不用,但效果是同样的.加号和 ...

随机推荐

  1. isinstance(object, classinfo) class type(name, bases, dict)

    w https://docs.python.org/3/library/functions.html#isinstance

  2. 插桩 inline hook 动态二进制插桩的原理和基本实现过程

    插桩测试 https://source.android.google.cn/compatibility/tests/development/instrumentation https://zhuanl ...

  3. sqlite时间类型

    SQLite分页显示:Select * From news order by id desc Limit 10 Offset 10这篇文章是根据 SQLite 官方 WIKI 里的内容翻译,如果有什么 ...

  4. 记录新建dorado项目更新规则中报错

    异常: Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Er ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_01 Collection集合_2_集合框架介绍

  6. 博客图片上传picgo工具安装配置github图传使用

    摘要 对于每一个写博客的人来说,图片是至关重要.这一路经历了多次图片的烦恼,之前选择了微博个人文章那里粘贴图片的方式上传,感觉也挺方便的.但是由于新浪的图片显示问题,如果header中不设置 标签就不 ...

  7. [Forward]C++ Properties - a Library Solution

    orig url: https://accu.org/index.php/journals/255 roperties are a feature of a number of programming ...

  8. vts测试流程

    测试前提: 1.发货user版本 2.selinux:Enable 3.连接ADB,stay awake 4.烧录XXX申请的key 5.外网环境(ipv6) ATV9测试准备(正常准备环境+fast ...

  9. [Python3 填坑] 018 组装类的几个例子

    目录 1. print( 坑的信息 ) 2. 开始填坑 2.1 MetaClass 举例 2.2 type 举例 2.3 MetaClass 举例 1. print( 坑的信息 ) 挖坑时间:2019 ...

  10. quartz任务调度的详解

    1.Quartz包含3个核心(调度器.作业类.触发器) (1).作业类:只需要实现org.quartz.job接口,同时包含里面的一个方法体execute()[这是被调度的作业体] (2).调度器:是 ...