题面在这里

再次破了纪录,连做了3天。。。

让我们从头来一点一点分析

1.预处理

先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路

我们发现n和m都比较大,但是k很小只有20,于是考虑状压dp

仔细读题我们会发现,题目里有这么一句话:为了走最短路,可以路过一个城市但不停留

所以这里我们先求单源最短路,不要被n的20000吓到,由于状态转移只发生在20个城市之间,所以只需要处理他们之间的最短路,别的都是打酱油的

读入数据建图,分别跑1至k+1每个点到20个点以及终点的最短路,堆优化dij板子就行spfa已经死了,然后存到数组里

对于限制条件,依次读入记录就可以,我开始担心条件之间的关系,比如1在2前面,2在3前面,从而有1就在3前面,就跑了一个传递闭包(知识点蓝书p360),实际上不用,一会解释

2.dp

状压dp肯定有一维是状态,这里就是用20位的二进制数表示状态

我开始的方程是第一维表示已经过的点数,第二维状态,第三维停在的城市

就有   f[i][j][u]=min(f[i][j][u],f[i-1][l][p]+d[p][u])

第一维可以滚掉,但这样有些浪费空间,不是很优

考虑优化,我第一回把第三维去掉了,这样基本相当于时间换空间,而且处理点之间限制关系时很容易出错,wa了一天果然还是太菜了。。。

实际上第一维是没啥用的,因为第一维的东西本来就可以从状态中表示出来(1的个数),而停的城市很关键,因为这关乎后面的转移

重来,第一维表示停在的城市,第二维是状态,就有

f[i][j]=min(f[i][j],f[p][l]+d[p][i])

这里的l是j的子状态,并且要满足l是j的任意一位的1变成0(有且仅有1位)

所以个人认为枚举的时候直接用lowbit相关运算枚举所有合法状态比较好,直接枚举再判断合法的时候限制可能有点多比较乱明明是你代码能力不行

i就是j和l差的那个一的位置,比如j=11100100,l=10100100,i就是7

p是在l上的一个1,比如上面那个例子,p枚举的就是3,6,8

如果i必须在p前面,说明状态转移不合法,直接continue

觉得然后大概思路就有了然后就调了两天

3.各种坑

首先是起点终点问题,原状态是本来在1,要走k个城市,故要走1-k+1,而且最后要停在n号,等于是又多了一个城市

我把每个序号都-1了,这样f[0][0]就是在1号不动,但是这样预处理也要跟着变,注意别整乱了,不然出来正无穷直接怀疑人生(大佬请无视)

如果你开始枚举的状态转移无法从0转移到1,就要提前把只经过1个城市的状态预处理

为了节约时空,我的dp只处理到k+1,最后的n再枚举取最小值,事实证明这样避免了特判出错

还有是在状态转移的时候,枚举到l是要先判断合不合法,因为l的所有点都是已经到过的,必须保证所有的p属于l,都有i不在p之前经过

只要有一个p不合法,整个l就不合法,都不能要,而不是只舍去对应的p接着枚举其他

这个地方卡的时间最长,改完39--80+。。。

时间的话,能用一波位运算解决的问题就不要调用自己写的函数,保证循环内操作o1

还有就是memset,初始化正无穷,但0x3f会出玄学错误,1e9也是,96分就因为这。。。,memset50是个好东西(8亿多),省时间的话可以改成for循环

k==0特判直接输出1-n最短路

4.卡空间

这题洛谷上空间异常的死,容易mle,两种思路,滚动数组或卡常

貌似都要把状态预处理

先鸽着

奉上拙劣的代码

  1 #include <bits/stdc++.h>
2 using namespace std;
3 struct node{
4 int from,to,v,next;
5 }a[400005];
6 int head[20005],mm=1;
7 inline void add(int x,int y,int z)
8 {
9 a[mm].from=x;a[mm].to=y;a[mm].v=z;
10 a[mm].next=head[x];head[x]=mm++;
11 }
12 int dis[20005];bool v[20005];
13 struct ttsc{
14 int c,d;
15 friend bool operator<(ttsc x,ttsc y)
16 {
17 return x.d>y.d;
18 }
19 };
20 priority_queue <ttsc> q;
21 inline void dj(int s)
22 {
23 memset(dis,0x3f,sizeof(dis));
24 memset(v,0,sizeof(v));
25 int x,y;ttsc cc;
26 cc.c=s,cc.d=0;
27 q.push(cc);
28 dis[s]=0;
29 while(!q.empty())
30 {
31 x=q.top().c;
32 y=q.top().d;
33 q.pop();
34 if(!v[x])
35 {
36 v[x]=1;
37 for(int i=head[x];i;i=a[i].next)
38 {
39 cc.c=a[i].to;
40 if(dis[cc.c]>y+a[i].v)
41 {
42 dis[cc.c]=y+a[i].v;
43 cc.d=dis[cc.c];
44 q.push(cc);
45 }
46 }
47 }
48 }
49 }
50 vector <int>state;
51 inline int lowbit(int x)
52 {
53 return x&(-x);
54 }
55 int dd[25][25];bool sb[25][25];int f[21][1100000];
56 int main()
57 {
58 int n,m,k,xz;
59 cin>>n>>m>>k;
60 for(int i=1;i<=m;i++)
61 {
62 int x,y,z;
63 scanf("%d%d%d",&x,&y,&z);
64 add(x,y,z);add(y,x,z);
65 }
66 for(int i=1;i<=k+1;i++)
67 {
68 dj(i);
69 for(int j=1;j<=k+1;j++)
70 dd[i-1][j-1]=dis[j];
71 dd[i-1][k+1]=dis[n];
72 }
73 cin>>xz;
74 for(int i=1;i<=xz;i++)
75 {
76 int x,y;
77 scanf("%d%d",&x,&y);
78 sb[x-1][y-1]=1;
79 }
80 if(k==0)
81 {
82 dj(1);
83 cout<<dis[n];
84 return 0;
85 }
86 // for(int i=0;i<=k+1;i++)sb[i][k+1]=1;这里如果枚举到k+1直接输出答案,就要有这句话
87
88 // for(int kk=0;kk<=k+1;kk++)
89 // for(int i=0;i<=k+1;i++)
90 // for(int j=0;j<=k+1;j++) 开始走的传递闭包,实际没用,因为不合法无法更新,
91 // sb[i][j]|=sb[i][kk]&sb[kk][j]; 如果加上,唯一好处就是一些不合法状态提前continue,也快不了多少
92 for(int i=0;i<=k;i++)
93 for(int j=0;j<=(1<<k)-1;j++)
94 f[i][j]=8e8;//不能太大 memset(f,50,sizeof(f))
95 int pmzg=1;
96 for(int i=1;i<=k+1;i++)
97 {
98 state.push_back(pmzg);
99 pmzg*=2;
100 }
101 for(int i=0;i<state.size();i++)f[i+1][state[i]]=dd[0][i+1];//预处理
102 f[0][0]=0;
103 for(int j=0;j<=(1<<(k))-1;j++)
104 {
105 for(int tem=j;tem;tem=(tem&(tem-1)))
106 {
107 int lt=lowbit(tem);
108 int u=log(lt)/log(2)+1;
109 int l=(j&(~lt));bool stop=0;
110 for(int p=1;p<=k;p++)//l是否合法
111 {
112 if(sb[u][p]&&((l>>(p-1))&1))
113 {stop=1;p=k;}
114 }
115 if(stop)continue;//舍去不合法状态
116 for(int p=1;p<=k;p++)
117 {
118 if(!((l>>(p-1))&1))continue;
119 f[u][j]=min(f[u][j],f[p][l]+dd[p][u]);
120 }
121 }
122 }
123 int ans=2147483600;
124 for(int i=1;i<=k;i++)
125 ans=min(ans,f[i][(1<<k)-1]+dd[i][k+1]);
126 cout<<ans;
127 return 0;
128 }

要有耐心一点点调,最后调出来的感觉真的不一样

执.

旅游景点 Tourist Attractions 题解的更多相关文章

  1. D. 旅游景点 Tourist Attractions 状压DP

    题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD 不希望在刚吃过一顿大餐之后立刻去下一 ...

  2. csp-s模拟48,49 Tourist Attractions,养花,画作题解

    题面:https://www.cnblogs.com/Juve/articles/11569010.html Tourist Attractions: 暴力当然是dfs四层 优化一下,固定两个点,答案 ...

  3. [Python爬虫] Selenium获取百度百科旅游景点的InfoBox消息盒

    前面我讲述过如何通过BeautifulSoup获取维基百科的消息盒,同样可以通过Spider获取网站内容,最近学习了Selenium+Phantomjs后,准备利用它们获取百度百科的旅游景点消息盒(I ...

  4. bzoj [POI2007]旅游景点atr 状态压缩+Dij

    [POI2007]旅游景点atr Time Limit: 30 Sec  Memory Limit: 357 MBSubmit: 2258  Solved: 595[Submit][Status][D ...

  5. 【BZOJ1097】[POI2007]旅游景点atr 最短路+状压DP

    [BZOJ1097][POI2007]旅游景点atr Description FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺 ...

  6. BZOJ1097: [POI2007]旅游景点atr

    ..k次最短路后,考虑如何满足先走一些点 用状压dp,每一个点考虑它所需要经过的点a[i],当当前走过的点包含a[i]时,i 这个点才可以到达. 写的时候用记忆化搜索. #include<bit ...

  7. 【BZOJ-1097】旅游景点atr SPFA + 状压DP

    1097: [POI2007]旅游景点atr Time Limit: 30 Sec  Memory Limit: 357 MBSubmit: 1531  Solved: 352[Submit][Sta ...

  8. BZOJ 1097: [POI2007]旅游景点atr( 最短路 + 状压dp )

    先最短路预处理, 然后状压就行了 -------------------------------------------------------------------------- #include ...

  9. BZOJ_1097_[POI2007]旅游景点atr_状压DP

    BZOJ_1097_[POI2007]旅游景点atr_状压DP 题面描述: FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣 的事情.经过这些城市的顺 ...

随机推荐

  1. 链表逆序---python

    class ListNode: Value = '' # 节点要储存的值,因为Python是弱类型,因此无需传入泛型 Next = None # 下一个节点,初始化时为空值 def __init__( ...

  2. WPF教程一:创建Hello world来理解XAML的内容及编译

    在实际的WPF开发中遇到很多再用Winform写法来写WPF的开发人员,很多时候项目进度延期.出现非必要的BUG等等.大多是因为开发人员虽然是再写WPF. 但是没有好好的学过WPF,就导致无法发挥出W ...

  3. linux挂载光驱

    挂载光驱到linux中.linux的镜像盘中有安装oracle的所有的软件包,可以会用yum一键安装. 1.此时的linux的界面显示光驱图标 2.挂载 因为光盘里面的文件是只读模式的,yum安装时不 ...

  4. Luogu P4313 文理分科

    link 最小割 双倍经验 这道题运用了最小割最常用的一种用法:集合划分. 因为源汇最小割即就是将源汇划分到不同的集合,那么最简单的应用就是最小代价划分集合了. 本题中,题意是将 \(n\cdot m ...

  5. 「CF986F」 Oppa Funcan Style Remastered

    「CF986F」 Oppa Funcan Style Remastered Link 首先发现分解成若干个 \(k\) 的因数很蠢,事实上每个因数都是由某个质因子的若干倍组成的,所以可以将问题转换为分 ...

  6. 5.Java流程控制

    所有的流程控制语句都可以相互嵌套.互不影响 一.用户交互Scanner Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户 ...

  7. QT从入门到入土(四)——多线程

    引言 前面几篇已经对C++的线程做了简单的总结,浅谈C++11中的多线程(三) - 唯有自己强大 - 博客园 (cnblogs.com).本篇着重于Qt多线程的总结与实现. 跟C++11中很像的是,Q ...

  8. element ui table表头动态筛选条件

    本文主要实现:根据el-table表格数据自动生成表头筛选条件的方法,可根据表格数据动态调整. el-table表格的表头增加筛选功能,大家平时都是怎么实现的呢?先看看官方文档的例子: 1 <t ...

  9. Postman进行webservices接口测试

    1.接口地址 webservices是什么? 更多webservices接口地址访问地址:http://www.webxml.com.cn/zh_cn/web_services.aspx webser ...

  10. Java 将Word转为XML,XML转为Word的方法

    本文介绍将Word和XML文档进行双向互转的方法.转换时,Word支持.docx/.doc等格式. 代码环境如下: Word测试文档:.docx或.doc 编译环境:IntelliJ IDEA JDK ...