分层图
模板
直接看一道裸题
Illegal Motor
分层图的典型应用,有K条免费边,除了原图外再建K层图。然后对于从每个点出的每一条边,连一条从此点到这条边终点所对应的上一层的点,边权为零,从一层到下一层相当于走了一条免费边。由于不需要走完所有的免费边,所以应取所有层的终点的最短路的最小值。
注意:存图的时候不要开小了,由于还要连跨层边,所以MAXN*(MAXK+1)是远远不够的
如图所示:
这里只画出来0号节点的免费边
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1e4,MAXM=5e4,MAXK=10,INF=~0U>>1;
int N,M,K;
int S,T;
struct E{int to,next,value;} e[4*MAXM*(MAXK+1)+MAXK+1];int ecnt,G[MAXN*(MAXK+1)+1];
void addEdge(int u,int v,int w){e[++ecnt]={v,G[u],w};G[u]=ecnt;}
void readInt(int & x)
{
x=0;
bool flag=false;
char c;
do c=getchar(); while(c!='-'&&(c<'0'||c>'9'));
if(c=='-') flag=true;
else x+=c-'0';
c=getchar();
while(c>='0'&&c<='9')
{
x*=10;
x+=c-'0';
c=getchar();
}
}
inline void read()
{
int i,j;
readInt(N);readInt(M);readInt(K);
readInt(S);readInt(T);
for(i=1;i<=M;i++)
{
int u,v,w;
readInt(u);readInt(v);readInt(w);
for(j=0;j<=K;j++)
{
addEdge(u+N*j,v+N*j,w);
addEdge(v+N*j,u+N*j,w);
if(j!=K)
{
addEdge(u+N*j,v+N*(j+1),0);
addEdge(v+N*j,u+N*(j+1),0);
}
}
}
}
struct HN{int id,v;bool operator<(const HN & ot)const{return v>ot.v;}};
priority_queue<HN> heap;
bool inS[MAXN*(MAXK+1)+1];
int dis[MAXN*(MAXK+1)+1];
void dijkstra(int v0)
{
int i;
for(i=1;i<=N*(K+1);i++) dis[i]=INF;
memset(inS,false,sizeof(inS));
dis[v0]=0;
heap.push((HN){v0,0});
while(!heap.empty())
{
int u=heap.top().id;heap.pop();
if(inS[u]) continue;
inS[u]=true;
for(i=G[u];i;i=e[i].next)
{
int v=e[i].to;
if(!inS[v])
if(dis[v]>dis[u]+e[i].value)
{
dis[v]=dis[u]+e[i].value;
heap.push((HN){v,dis[v]});
}
}
}
}
int main()
{
freopen("Motor.in","r",stdin);
freopen("Motor.out","w",stdout);
int i;
read();
dijkstra(S);
int ans=INF;
for(i=0;i<=K;i++) ans=min(ans,dis[T+N*i]);
printf("%d",ans);
return 0;
}