[POI2007]Tourist Attractions
题目大意:
给你一个$n(n\leq 2\times 10^4)$个点,$m(m\leq 2\times 10^5)$条边的带边权的连通图。其中有$k(k\leq 20)$个关键点。关键点之间有$g$条拓扑结构的依赖关系,每条依赖关系$(u,v)$描述点$v$依赖于点$u$,即点$u$必须在点$v$之前出现。若同时存在依赖关系$(u,v)$和$(v,w)$,则有依赖关系$(u,w)$。每个点可以经过多次,经过的可以不满足依赖关系。求一条从$1$到$n$的最短的路径,满足每个关键点至少有一次被经过时满足了依赖关系。
思路:
状压DP。
首先用Floyd预处理每个关键点依赖的点集$pre[i]$。然后用Dijkstra求出点$1$和每个关键点作为起点的单源最短路。
用$f[S][i]$表示已满足依赖关系的点集为$S$,当前路径上,最后一个结点为$i$。
预处理$f[i][i]=\left\{\begin{aligned}dis[1][i]&&{pre[i]=\varnothing}\\\infty&&pre[i]\neq\varnothing\end{aligned}\right.$。
转移方程为$f[S\bigcup i][i]=\min\{f[S][j]+dis[i][j]\mid i\notin S\land pre[i]\in S\}$。
答案$ans=\min{f[U][i]+dis[i][n]}$。
Floyd$O(k^3)$,配对堆优化Dijkstra$O(m+n\log n)$,动态规划$O(2^kk^2)$时间复杂度为$O(k^3+m+n\log n+2^kk^2)$。空间复杂度$O(2^kk)$。
在BZOJ上跑了9068 MS,内存89980 KB,Rank 2。但是POI原题内存是64 MB。
一种卡内存的方法是压缩一下状态,因为$f[S][i]$中$S$一定包括$i$,因此我们可以把$i$这一位去掉,然后把大于$i$的位往前移。空间除以一个常数,可以卡过。
还有一种做法是根据$S$中元素个数,将DP数组进行滚动,空间复杂度为$O(n\binom{k}{\lceil\frac{k}{2}\rceil})$。
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<functional>
#include<ext/pb_ds/priority_queue.hpp>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=,K=;
const int inf=INT_MAX;
struct Edge {
int to,w;
};
std::vector<Edge> e[N];
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].push_back((Edge){v,w});
e[v].push_back((Edge){u,w});
}
bool b[K][K];
int n,m,k,pre[K],dis0[N],dis[K][N],f[<<K][K];
struct Vertex {
int id,dis;
bool operator > (const Vertex &another) const {
return dis>another.dis;
}
};
void dijkstra(const int &s,int dis[]) {
static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> > q;
static __gnu_pbds::priority_queue<Vertex,std::greater<Vertex> >::point_iterator p[N];
for(register int i=;i<=n;i++) {
p[i]=q.push((Vertex){i,dis[i]=i==s?:inf});
}
while(!q.empty()) {
const int x=q.top().id;
q.pop();
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i].to,&w=e[x][i].w;
if(dis[x]+w<dis[y]) {
q.modify(p[y],(Vertex){y,dis[y]=dis[x]+w});
}
}
}
}
int main() {
n=getint(),m=getint(),k=getint();
for(register int i=;i<m;i++) {
const int u=getint(),v=getint(),w=getint();
add_edge(u,v,w);
}
if(k==) {
dijkstra(,dis0);
printf("%d\n",dis0[n]);
return ;
}
for(register int i=getint();i;i--) {
const int u=getint(),v=getint();
b[u-][v-]=true;
}
for(register int l=;l<k;l++) {
for(register int i=;i<k;i++) {
if(i==l||!b[i][l]) continue;
for(register int j=;j<k;j++) {
if(j==l||j==i||!b[l][j]) continue;
b[i][j]=true;
}
}
}
for(register int i=;i<k;i++) {
for(register int j=;j<k;j++) {
if(b[i][j]) pre[j]|=<<i;
}
}
dijkstra(,dis0);
for(register int i=;i<=k+;i++) {
dijkstra(i,dis[i-]);
}
for(register int state=;state<<<k;state++) {
for(register int i=;i<k;i++) {
f[state][i]=inf;
}
}
for(register int i=;i<k;i++) {
if(!pre[i]) f[<<i][i]=dis0[i+];
}
for(register int state=;state<<<k;state++) {
for(register int i=;i<k;i++) {
if(!(state&(<<i))&&(state&pre[i])==pre[i]) {
for(register int j=;j<k;j++) {
if(f[state][j]!=inf) {
f[state^(<<i)][i]=std::min(f[state^(<<i)][i],f[state][j]+dis[j][i+]);
}
}
}
}
}
int ans=inf;
for(register int i=;i<k;i++) {
if(f[(<<k)-][i]==inf) continue;
ans=std::min(ans,f[(<<k)-][i]+dis[i][n]);
}
printf("%d\n",ans);
return ;
}
[POI2007]Tourist Attractions的更多相关文章
- [POI2007]ATR-Tourist Attractions [TPLY]
[POI2007]ATR-Tourist Attractions 题目链接(https://www.luogu.org/problemnew/show/P3451) 这种稠密图还是建议你不要跑spfa ...
- csp-s模拟48,49 Tourist Attractions,养花,画作题解
题面:https://www.cnblogs.com/Juve/articles/11569010.html Tourist Attractions: 暴力当然是dfs四层 优化一下,固定两个点,答案 ...
- LYDSY模拟赛day1 Tourist Attractions
/* 假设路径是 a − b − c − d,考虑枚举中间这条边 b − c,计 算有多少可行的 a 和 d. 设 degx 表示点 x 的度数,那么边 b − c 对答案的贡献为 (degb − 1 ...
- 解题:POI 2007 Tourist Attractions
题面 事实上这份代码在洛谷过不去,因为好像要用到一些压缩空间的技巧,我并不想(hui)写(捂脸) 先预处理$1$到$k+1$这些点之间相互的最短路和它们到终点的最短路,并记录下每个点能够转移到时的状态 ...
- [POI2007]ATR-Tourist Attractions
题目大意:一个无向图,从$1$到$n$,要求必须经过$2,3,\dots,k+1$,给出一些限制关系,要求在经过$v\leq k+1$之前必须经过$u\leq k+1$,求最短路 题解:预处理出$1\ ...
- 【JZOJ4857】Tourist Attractions(Bitset)
题意:给定一个n个点的无向图,求这个图中有多少条长度为4的简单路径. n<=1500 思路: #include<map> #include<set> #include&l ...
- [CSP-S模拟测试]:Tourist Attractions(简单图论+bitset)
题目描述 在美丽的比特镇一共有$n$个景区,编号依次为$1$到$n$,它们之间通过若干条双向道路连接.$Byteasar$慕名来到了比特镇旅游,不过由于昂贵的门票费,他只能负担起$4$个景区的门票费. ...
- 比特镇旅游(Tourist Attractions)【暴力+Bitset 附Bitset用法】
Online Judge:NOIP2016十连测第一场 T2 Label:暴力,Bitset 题目描述 在美丽的比特镇一共有n个景区,编号依次为1到n,它们之间通过若干条双向道路连接. Byteasa ...
- D. 旅游景点 Tourist Attractions 状压DP
题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD 不希望在刚吃过一顿大餐之后立刻去下一 ...
随机推荐
- django之HTTPResponse和JsonResponse详解
HttpResponse对象 Django服务器接收到客户端发送过来的请求后,会将提交上来的这些数据封装成一个HttpRequest对象传给视图函数.那么视图函数在处理完相关的逻辑后,也需要返回一个响 ...
- linux中帮助参数 man whatis which info区别?
在linux终端,面对命令不知道怎么用,或不记得命令的拼写及参数时,我们需要求助于系统的帮助文档: linux系统内置的帮助文档很详细,通常能解决我们的问题,我们需要掌握如何正确的去使用它们: 在只记 ...
- web浏览器中的javascript
window 对象中其中一个最重要的属性是document,它引用document对象,后者表示显示在窗口中的文档.document对象有一些重要方法,比如getElementById(),它可以基于 ...
- Android记事本开发03
昨天: 生成签名文件及导出apk 遇到的问题: 无. 今天: activity和intent基础
- hdu 2616 Kill the monster (DFS)
Kill the monster Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- [NOI2015][bzoj4197] 寿司晚宴 [状压dp+质因数]
题面 传送门 思路 首先,要让两个人选的数字全部互质,那么有一个显然的充要条件:甲选的数字的质因数集合和乙选的数字的质因数集合没有交集 30pt 这种情况下n<=30,也就是说可用的质数只有10 ...
- 获取地址栏参数 - queryString(正则表达式版本)
获取所有query string function queryStringAll() { var reg = /(?:^|&)([^&]+)=([^&]+)(?=&|$ ...
- [LeetCode169]Majority Element
Majority Element Total Accepted: 58500 Total Submissions: 163658My Submissions Question Solution Gi ...
- ACdream 1023 抑或
Xor Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statisti ...
- js判断中出现两个!!是什么意思?
在js中看源码时有时候出现两个!!,我起初以为是js的其他语法,其实!!就是两次取“非”的运算. 下面证明我的说法. alert(null);//false alert(!null);//true a ...