【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra
题目描述
FGD想从成都去上海旅游。在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情。经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之后立刻去下一个城市登山,而是希望去另外什么地方喝下午茶。幸运的是,FGD的旅程不是既定的,他可以在某些旅行方案之间进行选择。由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够的精力来欣赏风景或者是泡MM了^_^.整个城市交通网络包含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需要的。
输入
第一行包含3个整数N(2<=N<=20000),M(1<=M<=200000),K(0<=K<=20),意义如上所述。
输出
只包含一行,包含一个整数,表示最短的旅行距离。
样例输入
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
样例输出
19
题解
状压dp+堆优化Dijkstra
题目给出$k\le 20$及每个点经过一次,显然状压dp。
不过由于点数非常多,因此不能以点数为状态,而是以关键点为状态。
设$f[i][j]$表示经过的点的状态为$i$,当前所在点为第$j$个关键点的最小路程。
考虑枚举下一个关键点,所走的路径一定是它们之间的最短路。
所以预处理出$1...k+1$到所有点的最短路,然后初始状态为$f[1<<i][i]=dis[1][i]$,转移时加上最短距离。
最后的答案就是$min(f[(1<<k)-1][i]+dis[i][n])$。
时间复杂度$O(k(n+m)\log n+2^k·k^2)$
#include <queue>
#include <cstdio>
#include <cstring>
#include <utility>
#define N 20010
#define M 400010
using namespace std;
typedef pair<int , int> pr;
priority_queue<pr> q;
int head[N] , to[M] , len[M] , next[M] , cnt , dis[22][N] , vis[N] , lim[N] , f[1 << 20][21];
void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void dijkstra(int s)
{
int i , x;
memset(dis[s] , 0x3f , sizeof(dis[s])) , memset(vis , 0 , sizeof(vis));
dis[s][s] = 0 , q.push(pr(0 , s));
while(!q.empty())
{
x = q.top().second , q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(dis[s][to[i]] > dis[s][x] + len[i])
dis[s][to[i]] = dis[s][x] + len[i] , q.push(pr(-dis[s][to[i]] , to[i]));
}
}
int main()
{
int n , m , d , p , i , j , k , x , y , z , ans = 1 << 30;
scanf("%d%d%d" , &n , &m , &d);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
for(i = 1 ; i <= d + 1 ; i ++ ) dijkstra(i);
scanf("%d" , &p);
for(i = 1 ; i <= p ; i ++ ) scanf("%d%d" , &x , &y) , lim[y - 1] |= (1 << (x - 2));
if(!d)
{
printf("%d\n" , dis[1][n]);
return 0;
}
memset(f , 0x3f , sizeof(f));
for(i = 1 ; i <= d ; i ++ )
if(!lim[i])
f[1 << (i - 1)][i] = dis[1][i + 1];
for(i = 1 ; i < 1 << d ; i ++ )
for(j = 1 ; j <= d ; j ++ )
if(i & (1 << (j - 1)))
for(k = 1 ; k <= d ; k ++ )
if(!(i & (1 << (k - 1))) && !(~i & lim[k]))
f[i | (1 << (k - 1))][k] = min(f[i | (1 << (k - 1))][k] , f[i][j] + dis[j + 1][k + 1]);
for(i = 1 ; i <= d ; i ++ ) ans = min(ans , f[(1 << d) - 1][i] + dis[i + 1][n]);
printf("%d\n" , ans);
return 0;
}
【bzoj1097】[POI2007]旅游景点atr 状压dp+堆优化Dijkstra的更多相关文章
- BZOJ_1097_[POI2007]旅游景点atr_状压DP
BZOJ_1097_[POI2007]旅游景点atr_状压DP 题面描述: FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣 的事情.经过这些城市的顺 ...
- BZOJ1097: [POI2007]旅游景点atr
..k次最短路后,考虑如何满足先走一些点 用状压dp,每一个点考虑它所需要经过的点a[i],当当前走过的点包含a[i]时,i 这个点才可以到达. 写的时候用记忆化搜索. #include<bit ...
- 2018.11.06 bzoj1097: [POI2007]旅游景点atr(最短路+状压dp)
传送门 预处理出不能在每个点停留之后才停留的点的状态. 对kkk个点都跑一次最短路存下来之后只需要简单状压一下就能过了吐槽原题空间64MB蒟蒻无能为力 然后用fillfillfill赋极大值的时候当m ...
- 【BZOJ1097】[POI2007]旅游景点atr 最短路+状压DP
[BZOJ1097][POI2007]旅游景点atr Description FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺 ...
- 【BZOJ-1097】旅游景点atr SPFA + 状压DP
1097: [POI2007]旅游景点atr Time Limit: 30 Sec Memory Limit: 357 MBSubmit: 1531 Solved: 352[Submit][Sta ...
- BZOJ 1097: [POI2007]旅游景点atr( 最短路 + 状压dp )
先最短路预处理, 然后状压就行了 -------------------------------------------------------------------------- #include ...
- bzoj [POI2007]旅游景点atr 状态压缩+Dij
[POI2007]旅游景点atr Time Limit: 30 Sec Memory Limit: 357 MBSubmit: 2258 Solved: 595[Submit][Status][D ...
- 【bzoj5197】[CERC2017]Gambling Guide 期望dp+堆优化Dijkstra
题目描述 给定一张n个点,m条双向边的无向图. 你要从1号点走到n号点.当你位于x点时,你需要花1元钱,等概率随机地买到与x相邻的一个点的票,只有通过票才能走到其它点. 每当完成一次交易时,你可以选择 ...
- [POI2007]旅游景点atr
Description FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD不希望在刚吃过一顿大餐之 ...
随机推荐
- java之接口相关知识
1.接口用interface来声明 //定义一个动物接口 public interface Animal{ public void eat(); public void travel(); } 2.接 ...
- python 补缺收集
[http://www.cnblogs.com/happyframework/p/3255962.html] 1. 高效code 与 不常用的函数用法: #带索引的遍历 , )): print(ind ...
- Tomcat启动xxx.keystore文件找不到
在server.xml里配置了 <Connector SSLEnabled="true" acceptCount="1000000" clientAuth ...
- redis redis-cli 操作指令
默认选择 db库是 0 redis-cli -p 6379 查看当前所在“db库”所有的缓存key redis 127.0.0.1:6379> keys * 选择 db库 redis 1 ...
- [mysql] Can't read from messagefile
系统:windows 重启mysql服务出现 Server] Can't read from messagefile 等错误时候, 应先执行 mysqld --initialize-insecure ...
- Linux更改文件权限(一)
更改文件权限(一)============================== (参考于千锋教育教学笔记) 设置权限 1.更改文件的属主.属组chown (change owner)[root@ami ...
- PHP namespace、abstract、interface、trait使用介绍
小菜鸟一枚,一直搞不懂 namespace.abstract.interface.trait 这些关系,就抽出几天时间研究,做个总结,不足之处希望大家指正交流. namespace 命名空间 介绍:顾 ...
- HashMap 排序
本文章,摘抄自:2018黑马程序最新面试题汇总 已知一个 HashMap<Integer,User>集合, User 有 name(String)和 age(int)属性.请写一个方法实现 ...
- flock文件锁
linux中的定时任务crontab会定时执行一些脚本,但是脚本的时间往往无法控制,当脚本的执行时间过长,可能会导致上一次任务的脚本还没执行完,下一次任务的脚本又开始执行的问题.这种情况下会出现一些并 ...
- 循环(while、for)
写重复的代码是程序员最不耻的行为,那么如何做到不用写重复代码又能让程序重复一段代码多次呢,循环语句就派上用场拉…… 一.while 循环 # while 语法结构 while 条件: 执行代码.... ...