分层图最短路问题详解
来源:互联网 发布:秋季女装蕾丝新款淘宝 编辑:程序博客网 时间:2024/06/05 15:30
分层图最短路,就是在分层图上解决最短路问题。
一般解决方法是多开一维记录状态,多开的维度记录状态的种类数即为分层数。
基本模型:在图上,有k次机会可以直接通过一条边而不计算边权,问起点与终点之间的最短路径。
例题:Bzoj 2763 飞行路线
http://www.lydsy.com/JudgeOnline/problem.php?id=2763
思路
我们设置dis[i][k]表示走到第i号点,免费经过了k条边的最短路。
对于我们当前找到的终点,尝试起点的状态去更新,不选择此条边免费的状态和选择此条边免费的状态,再将这两个状态压入队列去更新可以到达的其他状态。
代码可见:http://blog.csdn.net/qq_36312502/article/details/78313487
另外还有一部分其他类型的最短路问题可以用分层图的思想解决:
这种类型主要思路仍然是多开一维记录当前状态,然后根据当前状态更新其对应状态。
如:Codevs 1391 伊吹萃香,记录颜色
http://codevs.cn/problem/1391/
思路
我们设dis[i][j]表示走到第i号点,i号点颜色为j时的最短路。
我们每找到一个终点,首先尝试用起点状态去更新起点颜色不同的状态,再去更新终点在此时刻的状态,将终点状态压入队列更新其他状态。
注意对时间和颜色的细节处理..
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;const int INF = 1000000007;int n,m,ru,rv,rw,tot;int wl[100010],sl[100010],first[100010],nxt[100010],dis[100010][2];bool cl[100010],inq[100010][2];struct edge{ int u,v,w;}l[100010];struct point{ int num,c;}p[100010];queue<point>q;void build(int f,int t,int c){ l[++tot]=(edge){f,t,c}; nxt[tot]=first[f]; first[f]=tot;}void SPFA(){ for(int i=1;i<=n;i++) dis[i][0]=INF,dis[i][1]=INF,inq[i][0]=0,inq[i][1]=0; dis[1][cl[1]]=0; q.push((point){1,cl[1]}); inq[1][cl[1]]=1; while(!q.empty()) { point k=q.front(); q.pop(); inq[k.num][k.c]=0; if(dis[k.num][k.c^1]>dis[k.num][k.c]+(k.c)*sl[k.num])//更新颜色不同的状态 { dis[k.num][k.c^1]=dis[k.num][k.c]+(k.c)*sl[k.num]; if(!inq[k.num][k.c^1]) { q.push((point){k.num,k.c^1}); inq[k.num][k.c^1]=1; } } for(int i=first[k.num];i!=-1;i=nxt[i]) { int x=l[i].v,co=cl[x],val=l[i].w; if(k.c!=cl[k.num])//若发生了颜色变化即此时为奇数时刻 co^=1;//改变x的颜色 val=max(val+(k.c-co)*abs(wl[k.num]-wl[x]),0);//获取边权,最小为0 co^=1;//若可以更新最短路,经过这条边后颜色再次改变 if(dis[x][co]>dis[k.num][k.c]+val) { dis[x][co]=dis[k.num][k.c]+val; if(!inq[x][co]) { q.push((point){x,co}); inq[x][co]=1; } } } }}int main(){ memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&cl[i]); for(int i=1;i<=n;i++) scanf("%d",&wl[i]); for(int i=1;i<=n;i++) scanf("%d",&sl[i]); for(int i=1;i<=m;i++) { scanf("%d%d%d",&ru,&rv,&rw); build(ru,rv,rw); } SPFA(); printf("%d",min(dis[n][0],dis[n][1])); return 0;}
如Codevs 2070 爱情之路,记录当前节点是由哪种类型的边更新过来的。
http://codevs.cn/problem/2070/
思路
我们设dis[i][j]表示到第i号点,i号点是由j种类型的边更新来的,所得的的最短路。
我们每找到一个终点,用看这条边是否当前起点的状态的下一状态,符合则更新。
数据不友好加了一点特判。
还有一种思路是,设dis[i][j]表示到第i号点,经过了j条边的最短路,用j%4确定上一条边的类型…但空间显然不够无法验证
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>using namespace std;int n,m,ru,rv,rw,tot;char c;int first[500010],nxt[500010];int dis[500010][5],inq[500010][5];//dis[i][j]到第i号点是由怎样的边更新的 int step[500010][5]; int cnt[500010];bool flag; struct edge{ int u,v,w,num;}l[50010];struct ini{ int A,Z;};queue<ini>q;int read(){ char ch=getchar(); int ret=0; while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') { ret=ret*10+(ch-'0'); ch=getchar(); } return ret;}void build(int f,int t,int c,int u){ l[++tot]=(edge){f,t,c,u}; nxt[tot]=first[f]; first[f]=tot;}void SPFA(){ memset(dis,0X7f,sizeof(dis)); dis[1][4]=0; inq[1][4]=1; q.push((ini){1,4}); while(!q.empty()) { ini k=q.front(); q.pop(); inq[k.A][k.Z]=0; for(int i=first[k.A];i!=-1;i=nxt[i]) { int x=l[i].v; int t=(k.Z%4)+1; if(t!=l[i].num) continue; flag=1; if(dis[x][t]>=dis[k.A][k.Z]+l[i].w)//同一点的不同状态会被不同的点更新 { //注意等于的情况也要更新,因为我们还有统计步数要使步数尽量多 dis[x][t]=dis[k.A][k.Z]+l[i].w; step[x][t]=max(step[x][t],step[k.A][k.Z]+1);//使完成的考验尽量多 if(!inq[x][t]) { q.push((ini){x,t}); inq[x][t]=1; cnt[x]=max(cnt[k.A]+1,cnt[x]); if(cnt[x]>=n+2) return; } } } }}int main(){ memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { ru=read();rv=read();rw=read(); c=getchar(); while(c<'A'||c>'Z') c=getchar(); int tmp; if(c=='L') tmp=1; if(c=='O') tmp=2; if(c=='V') tmp=3; if(c=='E') tmp=4; build(ru,rv,rw,tmp); build(rv,ru,rw,tmp); } SPFA(); if(dis[n][4]==2139062143||!flag) //为什么要加flag呢?因为有一组数据全部全部都是1的自环且无法走到自己 printf("HOLY SHIT!"); else { if(dis[n][4]==0)dis[n][4]=4,step[n][4]=4;//全部为1的自环可以走的自己 printf("%d %d",dis[n][4],step[n][4]/4); } return 0;}
如2017.11.5莱芜一中互测,problem 2,由于n和m都比较小,状态种数2^15,可以用分层图做,二进制压位记录经过了哪些点。
- 分层图最短路问题详解
- hdu3499(分层图最短路)
- 分层图最短路 bzoj2763
- 汽车加油行驶问题(分层图最短路)
- 【codevs1912】汽车加油行驶问题 分层图最短路
- Aizu1311 分层图最短路 (...大概)
- [JLOI2011]飞行路线 分层图最短路
- NEFU 1132 分层图最短路
- [bzoj2763]飞行路线 分层图最短路
- BZOJ 2834(回家的路-分层图最短路)
- [BZOJ2763][JLOI2011][分层图最短路]飞行路线
- bzoj1922: [Sdoi2010]大陆争霸 分层图最短路
- bzoj2763: [JLOI2011]飞行路线 分层图最短路
- bzoj2662: [BeiJing wc2012]冻结 分层图最短路
- BZOJ 2763 JLOI 2011 飞行路线 分层图+最短路
- BZOJ2763 [JLOI2011]飞行路线(分层图最短路)
- 【JLOI2011】【bzoj2763】飞行路线 分层图最短路
- 【东方模拟题】伊吹萃香 分层图最短路
- JQuery基礎.show();.hide();
- 聊聊面向对象的几个基本原则
- 关于Jquery错误的解决:Uncaught TypeError: $.post is not a function
- G 零崎的朋友很多Ⅱ(0-1背包修改版 )
- 21.3 命中率测量
- 分层图最短路问题详解
- 返回指定时间段相同间隔数组
- 爬楼梯
- [实时渲染] 3. 图形处理单元-GPU
- vue-router中参数传递 + 编程式导航 + beforeRouteEnter
- 获取的android手机的MAC地址
- tf.基本操作,重点是有变量切片
- js判断null,NaN,undefined,空字符串
- 丛林战争项目四之客户端连接正常和非正常关闭