题目描述

给出一张有 \(n\) 个点 \(m\) 条边的无向图,每条边有边权。

你需要找一条从 \(1\) 到 \(n\) 的最短路径,并且这条路径在满足给出的 \(g\) 个限制的情况下可以在所有编号从 \(2\) 到 \(k+1\) 的点上停留过。

每个限制条件形如 \(r_i, s_i\),表示停留在 \(s_i\) 之前必须先在 \(r_i\) 停留过。

注意,这里的停留不是指经过

解法分析

对于这道题的状压. 我们考虑枚举 "现在已经在哪些点停留" 这样一种状态. 然后去寻找每一个当前未停留的点,考虑这个点的前置节点是否全部已经停留,如果是,那么枚举每一个已在集合内的节点,尝试把这个点通过某条边放入集合内,进行状态转移.

那么我们需要进行状态压缩的有两个东西: 现在已有的点的情况 (用于枚举) 和每个点的前置节点情况 (用于判断).

最后需要我们输出的就是在全部节点停留情况下的状态.

这道题的主要思路:

for(int i=1;i<=(1<<k)-1;++i){
//all possible chance
for(int j=0;j<=k-1;++j){ //node
if(i&(1<<j)){
//if this node in this chance
for(int hdk=0;hdk<=k-1;++hdk){
//then try to add a node
if(!(i&(1<<hdk))&&((i|r[hdk+2])==i)){
//if find a node not in chance and can be placed
update();
}
//then do the change. why it's +2 is because I store 3 in position 1.(1 and 2 is no need)
}
}
}
}

那么,为了更新已选中的点的距离,我们需要知道从任意点到另一点的距离,也就是跑一边全源最短路.

我们定义 \(dis[i][j]\) 为全源最短路下的 \(i,j\) 最短距离. \(r[i]\) 表示 \(i\) 的全部前置节点的状压表示. \(f[i][j]\) 表示在已经选择 \(i\) (状压表示) 这些节点的情况下,且最后一个选中的节点为 \(j\) 的最短路径长度. 那么我们有:

\[f[i\ add\ k][k]=min(f[i\ add\ k][k],min\sum^{j}_{j\in i}(f[i][j]+dis[j][k]))
\]

那么我们怎么表示 \(i\ add\ k\) 呢. 其实只需要将 \(i\) 中的 \(k\) 点的位置置为 \(1\). 也就是做一次或运算.

这题我也不知道它卡什么. 我存图的 vector 滚动数组会比前向星小很多,而 DIJ 又比 SPFA 快很多. 总之按对的来吧.

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
struct edge{
int to,w;
};
struct node{
int id,dis;
bool operator<(const node A)const{
return dis>A.dis;
}
};
priority_queue<node> q;
vector<edge> e[20001];
int dis[31][20001]; //root i's dis j
bool vis[20001];
void dij(int s){
memset(vis,false,sizeof vis);
for(int i=1;i<=n;++i){
dis[s][i]=1000000000;
}
while(!q.empty()) q.pop();
dis[s][s]=0;
q.push(node{s,0});
while(!q.empty()){
node u=q.top();
q.pop();
if(vis[u.id]) continue;
vis[u.id]=true;
for(edge i:e[u.id]){
if(dis[s][i.to]>dis[s][u.id]+i.w){
dis[s][i.to]=dis[s][u.id]+i.w;
q.push(node{i.to,dis[s][i.to]});
}
}
}
}
int f[1<<20][31],r[31],ans=1000000000; //1=zt(which nodes been chose) 2=node //r= mustfore
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;++i){
int a,b,c;
cin>>a>>b>>c;
e[a].push_back(edge{b,c});
e[b].push_back(edge{a,c});
}
if(k==0){
dij(1);
cout<<dis[1][n];
return 0;
}
int q;
cin>>q;
while(q--){
int a,b;
cin>>a>>b;
r[b]+=(1<<(a-2));//
}
for(int i=1;i<=k+1;++i){
dij(i);
}
for(int i=0;i<=(1<<k)-1;++i){
for(int j=1;j<=k+1;++j){
f[i][j]=1000000000;
}
}
f[0][1]=0;
for(int i=2;i<=k+1;++i){
if(!r[i]){ //if this point hasn't any requires.
f[1<<(i-2)][i]=dis[1][i];
}
}
for(int i=1;i<=(1<<k)-1;++i){ //all possible chance
for(int j=0;j<=k-1;++j){ //node
if(i&(1<<j)){ //if this node in this chance
for(int hdk=0;hdk<=k-1;++hdk){ //then try to add a node
if(!(i&(1<<hdk))&&((i|r[hdk+2])==i)){ //if find a node not in chance and can be placed
f[i|(1<<hdk)][hdk+2]=min(f[i|(1<<hdk)][hdk+2],f[i][j+2]+dis[j+2][hdk+2]);
} //then do the change. why it's +2 is because I store 3 in position 1.(1 and 2 is no need)
}
}
}
}
for(int i=2;i<=k+1;++i){
ans=min(ans,f[(1<<k)-1][i]+dis[i][n]);
}
cout<<ans;
}

洛谷数据需要滚动数组优化,正在写.

[TK] Tourist Attractions的更多相关文章

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

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

  2. LYDSY模拟赛day1 Tourist Attractions

    /* 假设路径是 a − b − c − d,考虑枚举中间这条边 b − c,计 算有多少可行的 a 和 d. 设 degx 表示点 x 的度数,那么边 b − c 对答案的贡献为 (degb − 1 ...

  3. 解题:POI 2007 Tourist Attractions

    题面 事实上这份代码在洛谷过不去,因为好像要用到一些压缩空间的技巧,我并不想(hui)写(捂脸) 先预处理$1$到$k+1$这些点之间相互的最短路和它们到终点的最短路,并记录下每个点能够转移到时的状态 ...

  4. [POI2007]Tourist Attractions

    题目大意: 给你一个$n(n\leq 2\times 10^4)$个点,$m(m\leq 2\times 10^5)$条边的带边权的连通图.其中有$k(k\leq 20)$个关键点.关键点之间有$g$ ...

  5. 【JZOJ4857】Tourist Attractions(Bitset)

    题意:给定一个n个点的无向图,求这个图中有多少条长度为4的简单路径. n<=1500 思路: #include<map> #include<set> #include&l ...

  6. [CSP-S模拟测试]:Tourist Attractions(简单图论+bitset)

    题目描述 在美丽的比特镇一共有$n$个景区,编号依次为$1$到$n$,它们之间通过若干条双向道路连接.$Byteasar$慕名来到了比特镇旅游,不过由于昂贵的门票费,他只能负担起$4$个景区的门票费. ...

  7. 比特镇旅游(Tourist Attractions)【暴力+Bitset 附Bitset用法】

    Online Judge:NOIP2016十连测第一场 T2 Label:暴力,Bitset 题目描述 在美丽的比特镇一共有n个景区,编号依次为1到n,它们之间通过若干条双向道路连接. Byteasa ...

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

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

  9. 旅游景点 Tourist Attractions 题解

    题面在这里 再次破了纪录,连做了3天... 让我们从头来一点一点分析 1.预处理 先看题面,乍一看貌似是个图论题,有n个点m条边,给定一些必须经过的点和强制经过顺序,求一条最短路 我们发现n和m都比较 ...

  10. noip2016十连测round1

    A:String Master 题目:所谓最长公共子串,比如串 A:"abcde",串 B:"jcdkl",则它们的最长公共子串为串 "cd" ...

随机推荐

  1. locust多进程实现分布式压测遇到的问题

    多进程分布式的实现: locust分布式时,需借助命令locust 一个一个启动worker,在使用中有点繁琐, 下面借助于多进程,按既定worker数量,一键启动: from locust impo ...

  2. java srpint boot 2.2.1 第二部份,乐观锁机制, 构造复杂查询条件,分页查询 相关内容,删除与软删除

    第二部份,引起锁机制的原理和解决方案: 测试环境搭建第一步先建一个数据库表用于模拟商品购买. CREATE TABLE product ( id INT AUTO_INCREMENT PRIMARY ...

  3. scratch源码下载 | 炮轰僵尸

    程序说明: <炮轰僵尸>是一款基于Scratch平台制作的游戏程序,它采用了植物大战僵尸的经典场景.在游戏中,玩家需要控制一枚大炮来对抗不断入侵的僵尸.通过移动鼠标,玩家可以调整炮筒的方向 ...

  4. 【Vue2】Router 路由

    1.什么是单页面应用程序 单页面应用程序(英文名: Single Page Application)简称SPA, 顾名思义,指的是一个Web网站中只有唯一-的一-个HTML页面, 所有的功能与交互都在 ...

  5. 【郝斌C ST】指针 swap问题

    C语言 指针 swap问题 在主函数种实现变量的交换 现在我们把这交换的行为封装进方法中 swap函数确实进行了交换,打印也是10和5了,但是下面a和b的结果还是5和10 - 形参i 和 形参j 并不 ...

  6. 【Project】原生JavaWeb工程 03 单表的业务功能

    年级表效果图样例: 可以看到主要分为以下这些功能: 功能一:展示年级列表 功能二:每个年级都具备修改和删除 功能三:添加一个年级 功能四:对多个年级选中删除,也可以全选删除,或者反选删除 功能五:根据 ...

  7. vue导入项目缺少依赖‘node_modules’

    从git下载好的项目,导入vue时提示'node_modules'依赖 则需要在你的项目包下面找是否有package-lock.json文件,如: 如果有,但是依旧报错,直接删除package-loc ...

  8. Human-centric Computing and Information Sciences期刊基本信息

    letpub 地址: https://www.letpub.com.cn/index.php?page=journalapp&view=detail&journalid=10450&a ...

  9. 光刻机巨头ASML公布了其最新的品牌短片《站在巨人的肩膀上》

    光刻机巨头ASML公布了其最新的品牌短片<站在巨人的肩膀上>: 荷兰光刻机:ASML使用AI工具midjourney和runway制作宣传片 这个时长1分50秒短片的特别地方在于,它是完全 ...

  10. Android网页投屏控制从入门到放弃

    背景 业务需要采集在app上执行任务的整个过程,原始方案相对复杂,修改需要协调多方人员,因而考虑是否有更轻量级的方案. 原始需求: 记录完成任务的每一步操作(点击.滑动.输入等) 记录操作前后的截图和 ...