【分层图最短路】【学习笔记】


【分层图最短路】【学习笔记】

例题1
分析:
设f[i][j]为从1走到i,已指定j条路径边权为0,边权和的最小值,那么有
f[i][j]+w[i,y]——>f[y][j],
f[i][j]——>f[y][j+1],\((i,y)\in E\)
f[1][0]=0.
则答案为f[n][k]
实际上就是求从(1,0)到(n,k)的最短路,但可以不用真的建出分层图,注意判断不要让j超过k。
因为边权非负,用dij转移即可。

Code

#include
using namespace std;
//#define int long long
inline int read()
{
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) putchar('-'),x=~(x-1);
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=1e4+100;
int n,m,k,d[N][22],vis[N][22];
int hd[N],cnt;
struct node{
	int nxt,to,w;
}e[N*10];
void add(int x,int y,int z)
{
	e[++cnt].nxt=hd[x];
	e[cnt].w=z;
	e[cnt].to=y;
	hd[x]=cnt;
} 
priority_queue > >q;
void dij()
{
	memset(d,0x3f,sizeof d);
	d[1][0]=0;
	q.push(make_pair(0,make_pair(1,0)));
	while(q.size())
	{
		pairx=q.top().second;q.pop();
		int f=x.first,s=x.second;
		if(vis[f][s]) continue;
		vis[f][s]=1;
		for(int i=hd[f];i;i=e[i].nxt)
		{
			int y=e[i].to;
			if(d[y][s]>d[f][s]+e[i].w) d[y][s]=d[f][s]+e[i].w,q.push({-d[y][s],{y,s}});
			if(sd[f][s]) d[y][s+1]=d[f][s],q.push({-d[y][s+1],{y,s+1}});
		}
	}
}
int main()
{
    n=read();m=read();k=read();
    for(int i=1;i<=m;++i)
    {
    	int x=read(),y=read(),z=read();
    	add(x,y,z);add(y,x,z);
	}
	dij();
	write(d[n][k]);
	return 0;
}

例题2
与上一题类似,用dij求解即可。

Code

#include
using namespace std;
//#define int long long
inline int read()
{
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) putchar('-'),x=~(x-1);
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=55,M=1e3+100;
int hd[N],cnt;
struct node{
	int nxt,to,w;
}e[M<<1];
void add(int x,int y,int z)
{
	e[++cnt].w=z;
	e[cnt].to=y;
	e[cnt].nxt=hd[x];
	hd[x]=cnt;
}
int f[N][N],n,m,k,vis[N][N];
priority_queue > >q;
void dij()
{
	memset(f,0x3f,sizeof f);
	for(int i=0;i<=k;++i) f[1][i]=0,q.push({0,{1,i}});
	while(q.size())
	{
		int x=q.top().second.first,y=q.top().second.second;q.pop();
		if(vis[x][y]) continue;
		vis[x][y]=1;
		if(x==n&&y==k) return; 
		for(int i=hd[x];i;i=e[i].nxt)
		{
			int j=e[i].to;
			if(f[j][y]>f[x][y]+e[i].w)f[j][y]=f[x][y]+e[i].w,q.push({-f[j][y],{j,y}});
			if(yf[x][y]+e[i].w/2) f[j][y+1]=f[x][y]+e[i].w/2,q.push({-f[j][y+1],{j,y+1} });
		}
	}
}
signed main()
{
    n=read();m=read();k=read();
    for(int i=1;i<=m;++i)
    {
    	int x=read(),y=read(),z=read();
    	add(x,y,z);add(y,x,z);
	}
	dij();
	write(f[n][k]);
	return 0;
}

总结:
分层图最短路可以看做一种特殊的dp,列出状态转移方程以后,利用最短路算法来求解即可。
另外,分层图中的边一般不用真的建出来,这样也可以节省空间复杂度。