题面在这里

再次破了纪录,连做了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. Robotframework学习笔记之一Common Resource导入的Library库显示红色(导入失败)

    第一次使用Robotframework,所以也遇到了很多的坑,导入项目后 ,一些自带的库显示红色,导入失败!(ps:自带的库也显示红色) Ride日志如下(Tools--view ride log): ...

  2. SpEL表达式总结(转)

    前言 SpEL(Spring Expression Language),即Spring表达式语言,是比JSP的EL更强大的一种表达式语言.为什么要总结SpEL,因为它可以在运行时查询和操作数据,尤其是 ...

  3. 74cms v5.0.1 前台sql注⼊复现

    漏洞简介 74cms 5.0.1 前台AjaxPersonalController.class.php存在SQL注⼊ 复现过程 具体信息 文件位置 74cms\upload\Application\H ...

  4. 开源的负载测试/压力测试工具 NBomber

    负载测试和压力测试对于确保 web 应用的性能和可缩放性非常重要. 尽管它们的某些测试是相同的,但目标不同. 负载测试:测试应用是否可以在特定情况下处理指定的用户负载,同时仍满足响应目标. 应用在正常 ...

  5. 题解 CF311B Cats Transport

    前置芝士:斜率优化  剥下这道题的外壳,让它变为一道裸的斜率优化. 很容易想到状态,但复杂度显然过不去,也没有单调性,只能自己创造. 令 $$c[i] = t - sum[i],sum[i] = \s ...

  6. 前端-Vue基础3(父子组件交互)

    1.子组件往父组件传值 点击子组件的值,子组件自增,父组件的值也跟着自增 通过:this.$emit('change')方法向父组件暴露事件,在子组件中引用,可以调用父组件的方法 点击子组件触发cli ...

  7. 5000字2021最新Python基础知识第一阶段:数据类型

    1 编程规范 注释 python注释也有自己的规范,在文章中会介绍到.注释可以起到一个备注的作用,团队合作的时候,个人编写的代码经常会被多人调用,为了让别人能更容易理解代码的通途,使用注释是非常有效的 ...

  8. C语言:FILE p和FILE *p

    FILE p和FILE *p大概可以这么理解:1 . 前一个p指文件型变量,后一个p指文件地址型变量.2 . 前一个p的内存地址已定,后一个p内存地址未定. 前一个是声明类对象,后一个是声明一个可指向 ...

  9. 高校表白App-团队冲刺第六天

    今天要做什么 在引导页的基础上添加小红点,并且在滑动时进行增强用户体验的修饰 做了什么 在布局中成功添加小红点,并在activity中得到实现;滑动在3/4时发生渐变,增强用户体验;滑动可回退;在最后 ...

  10. [010] - JavaSE面试题(十):集合之Map

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [010] - JavaSE面试题(十):集合之Map 第1问:HashMap和HashTable ...