【BJOJ1097】旅游景点 atr (spfa+状压dp)
来源:互联网 发布:客户无忧软件 编辑:程序博客网 时间:2024/04/28 01:57
题目描述
FGD想从成都去上海旅游。由于FGD非常讨厌乘车的颠簸,他希望在满足他的要求的情况下,旅行的距离尽量短,这样他就有足够
的精力来欣赏风景。
整个城市交通网络包含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需要的。
输入
第1行包含3个整数N(2< =N< =20000), M(1<=M<=200000),K(0< =K<=20)
第2..M+1行,每行包含3个整数X,Y,Z,(1 ≤ x < y ≤N, 1 ≤z ≤ 1000).表示城市x到城市y距离为z,数据保证必然存在一条路径从城市
1到城市n, 经过所有城市。
第M+2行,一个整数g, 0 ≤ g ≤k·(k−1)/2。表示FGD停留的限制条件有g个。
第M+3..M+2+g行,包含2个整数ri和si ,2 ≤ ri ≤ k +1, 2 ≤ si ≤ k +1, ri不等于si。FGD访问城市si之前,必须访问ri。
输出
只包含一行,包含一个整数,表示最短的旅行距离
思路
分析发现k个点的先后到达顺序影响答案,其他点无论何时访问对于答案的贡献是固定的。因此可以先把研究范围缩小到这k个点
中。鉴于k的大小比较友善,可以考虑状压这k个点的状态(已访问/未访问)。
先spfa预处理出这k个点到每个点的最短距离,设f[i][j]表示状态i下最后到达第j个点的最小最短路程,不难得出转移式:
f[s][i]=min(f[s'][j]+dis[i][j])
对于访问某些点之前必须先访问其他点的限制条件,不妨同样通过状压的方式存下访问点i之前必须访问的点,在在转移的时候跳过非法状态即可。
#include <queue>#include <cstdio>#include <iostream> using namespace std; const int MAXN=20010;const int MAXM=200010;const int MAXK=22;const int INF=1e9; int n,m,k,g;bool inq[MAXN]; int head[MAXN],tot,lim[MAXK],f[1<<20][MAXK],dis[MAXK][MAXN],ans=INF;struct edge{int to,nxt,c;}e[MAXM<<1]; int getint(){ int v=0; char ch; while(!isdigit(ch=getchar())); v=ch-48; while(isdigit(ch=getchar())) v=v*10+ch-48; return v;} void insert(int u,int v,int cost){ e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].c=cost; e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].c=cost;} void spfa(int S){ for(int i=1;i<=n;i++) dis[S][i]=INF; dis[S][S]=0; queue<int> Q; Q.push(S); inq[S]=true; while(!Q.empty()){ int now=Q.front(); Q.pop(); for(int i=head[now];i;i=e[i].nxt){ if(dis[S][e[i].to]>dis[S][now]+e[i].c){ dis[S][e[i].to]=dis[S][now]+e[i].c; if(!inq[e[i].to]){ Q.push(e[i].to); inq[e[i].to]=true; } } } inq[now]=false; }} int main(){ n=getint(); m=getint(); k=getint(); for(int i=1;i<=m;i++){ int a=getint(),b=getint(),c=getint(); insert(a,b,c); } g=getint(); for(int i=1;i<=g;i++){ int a=getint(),b=getint(); lim[b]|=(1<<(a-2)); } for(int i=1;i<=k+1;i++) spfa(i); for(int i=0;i<(1<<k);i++) for(int j=1;j<=k+1;j++) f[i][j]=INF; for(int i=1;i<=k+1;i++) if(!lim[i]) f[1<<(i-2)][i]=dis[1][i]; for(int i=0;i<(1<<k);i++){ for(int j=1;j<=k+1;j++){ if(f[i][j]==INF) continue; for(int l=1;l<=k+1;l++){ if((lim[l]&i)!=lim[l]) continue; f[i|(1<<(l-2))][l]=min(f[i|(1<<(l-2))][l],f[i][j]+dis[l][j]); } } } for(int i=1;i<=k+1;i++) ans=min(ans,f[(1<<k)-1][i]+dis[i][n]); printf("%d\n",ans); return 0;}
- 【BJOJ1097】旅游景点 atr (spfa+状压dp)
- bzoj1097[POI2007]旅游景点atr spfa+状压DP
- BZOJ 1097 POI2007 旅游景点atr SPFA+状压DP
- BZOJ 1097: [POI2007]旅游景点atr spfa+状压dp
- [BZOJ1097][POI2007]旅游景点atr(状压dp)
- [BZOJ1097][POI2007]旅游景点atr(状压dp)
- bzoj 1097: [POI2007]旅游景点atr(状压DP)
- 1097: [POI2007]旅游景点atr dijkstra+状压dp
- bzoj1097: [POI2007]旅游景点atr[最短路预处理+状压dp]
- BZOJ 1097 [POI2007]旅游景点atr dijikstra+状压DP
- 旅游景点atr
- 【BZOJ1097】[POI2007]旅游景点atr【最短路】【状压DP】【记忆化搜索】
- BZOJ1097: [POI2007]旅游景点atr
- BZOJ1097: [POI2007]旅游景点atr
- BZOJ1097: [POI2007]旅游景点atr
- BZOJ1097 [POI2007]旅游景点atr
- BZOJ 1097: [POI2007]旅游景点atr 状压,预处理,最短路
- BZOJ 1097 [POI2007]旅游景点atr
- Android N代码分析:requestLayout
- android studio 2.0 导入项目
- 兹瓷分裂合并的线段树~(Segment tree Beats!Ⅱ)
- SMB协议
- leetcode题解-242.Valid Anagram
- 【BJOJ1097】旅游景点 atr (spfa+状压dp)
- iOS 图像压缩 图像选择的使用
- Manacher算法 求最长回文字串
- 当Gson解析遇上关键字
- 【poj3237】 Tree
- 小项目组迭代总结流程
- React Native 搭建开发环境
- Python中的random模块
- 用GDB调试程序