专题:分层图
拖了整整一个月,我终于来学习分层图了,原因是考一道 USACO 的题正解死分层图,
秉持着竟然有用,那我就来学学的原则,学习了分层图。
纵然,这确实是个好东西,但是局限性也比较明显 ,分层图的分层的意思是把图整体复制几遍,跨层走意味着使用了一次特殊机会。
但是,显然这对数据范围有严格要求,图的边和点乘以我的层数不能太大,不然就凉了。
一般建完图以后就是跑一个最短路,这里有一个非常需要重视的地方,就是对最短路算法的选择,有负权的时候切记使用 SPFA,其他一律 Dijkstra,不然会超时
例题
- [洛谷 P4568 JLOI2011] 飞行路线——解题报告
- [洛谷P1073 NOIP2009 提高组] 最优贸易—— 解题报告
- [洛谷P4822 BJWC2012] 冻结
- [洛谷P2939 USACO09FEB] Revamping Trails G
练完发现都是一个套路,就是路径中给你一些优惠,比如说 \(k\) 次机会让路免费,又或者是减半。其中只有第二题 最优贸易 需要根据题意转换一下思路。
这里放最后一题的代码,很好理解,基本就是一个建图思路。
然后注意如果题面中写到不一定要把 \(k\) 个优惠用完的话,那要记得把每一层的终点给连接起来。
#include<bits/stdc++.h>
using namespace std;
#define N 4500000
int n,m,k,fir[N],nex[N],tot=0,w[N],to[N];
int dis[N],vis[N];
void add(int x,int y,int z){
// printf("%d %d\n",x,y);
nex[++tot]=fir[x];
fir[x]=tot;
to[tot]=y;
w[tot]=z;
}
typedef pair<int,int> PII;
void dijkstra(){
memset(dis,0x3f,sizeof(dis));
dis[1]=0;
priority_queue<PII,vector<PII>,greater<PII> >p;
p.emplace(0,1);
while(!p.empty()){
int u=p.top().second;
p.pop();
if(!vis[u]){
vis[u]=1;
for(int e=fir[u];e;e=nex[e]){
int v=to[e];
if(dis[v]>dis[u]+w[e]){
dis[v]=dis[u]+w[e];
p.emplace(dis[v],v);
}
}
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);add(y,x,z);
for(int j=1;j<=k;j++){
add(j*n+x,j*n+y,z);
add(j*n+y,j*n+x,z);
add((j-1)*n+x,j*n+y,0);
add((j-1)*n+y,j*n+x,0);
}
}
for(int i=1;i<=k;i++){
add((i-1)*n+n,i*n+n,0);
}
dijkstra();
printf("%d",dis[n*(k+1)]);
return 0;
}
标签:fir,专题,洛谷,int,tot,分层,dis
From: https://www.cnblogs.com/alloverzyt/p/17825201.html