http://acm.hdu.edu.cn/showproblem.php?pid=6331

Problem Description
There are n intersections in Bytetown, connected with m one way streets. Little Q likes sport walking very much, he plans to walk for q days. On the i-th day, Little Q plans to start walking at the si-th intersection, walk through at least ki streets and finally return to the ti-th intersection.
Little Q’s smart phone will record his walking route. Compared to stay healthy, Little Q cares the statistics more. So he wants to minimize the total walking length of each day. Please write a program to help him find the best route.

题意:n(50)个点,m条边,q(10万)次询问,每次查询u到v至少经过k(1万)条边的最短路径。
思路:
不加优化的dp要 O ( n 3 k m a x ) O(n^3*k_{max}) O(n3kmax),超时太多。
考虑分块,每块大小 M = k m a x = 100 M=\sqrt{k_{max}}=100 M=kmax =100,分成100块。
d1,d2,d3分别是恰好走k条边,恰好走 k M k*M kM条边,至少走k条边
d 1 ( k , i , j ) = m i n { d 1 ( k 1 , i , x ) + d 1 ( 1 , x , j ) } d1(k,i,j)=min\{d1(k-1,i,x)+d1(1,x,j)\} d1(k,i,j)=min{d1(k1,i,x)+d1(1,x,j)} k &lt; = 100 k&lt;=100 k<=100
d 2 ( k , i , j ) = m i n { d 2 ( k 1 , i , x ) + d 2 ( 1 , x , j ) } d2(k,i,j)=min\{d2(k-1,i,x)+d2(1,x,j)\} d2(k,i,j)=min{d2(k1,i,x)+d2(1,x,j)} k &lt; = 100 k&lt;=100 k<=100
d 3 ( k , i , j ) = m i n { d 1 ( k , i , x ) + d ( x , j ) } d3(k,i,j)=min\{d1(k,i,x)+d(x,j)\} d3(k,i,j)=min{d1(k,i,x)+d(x,j)} k &lt; = 100 k&lt;=100 k<=100 注意要更新到k==0的情况
或者 d 3 ( k , i , j ) = m i n { d 3 ( k , i , j ) , d 3 ( k + 1 , i , j ) } d3(k,i,j)=min\{d3(k,i,j),d3(k+1,i,j)\} d3(k,i,j)=min{d3(k,i,j),d3(k+1,i,j)},但要把 d 1 d1 d1 d 3 d3 d3的k开到150而非100,原因如下:n=50,两点之间如果不走环最多走49条边,>49的话要么不可行,要么走环,有可能算至少走99条边的最短路时,恰好99条边到达不了,需要多开一个n的大小,保证可以到达。
处理询问时,枚举中间结点x,算u->x整块+x->v块内最小的。
预处理复杂度 O ( M n 3 ) O(Mn^3) O(Mn3),查询复杂度 O ( q n ) O(q*n) O(qn)

这篇blog讲的极好https://blog.csdn.net/weixin_42068627/article/details/81299321

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

int T,n,m,q;
int d1[151][51][51],d2[101][51][51];

void dp()
{
	for(int k=2;k<=150;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d1[k][i][j]=min(d1[k-1][i][x]+d1[1][x][j],d1[k][i][j]);
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			d2[1][i][j]=d1[100][i][j];
	for(int k=2;k<=100;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d2[k][i][j]=min(d2[k-1][i][x]+d2[1][x][j],d2[k][i][j]);

	for(int k=149;k>=0;k--)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d1[k][i][j]=min(d1[k+1][i][j],d1[k][i][j]);
}

int main()
{
	//freopen("input.in","r",stdin);
	cin>>T;
	while(T--)
	{
		int u,v,w;
		cin>>n>>m;
		memset(d1,INF,sizeof(d1));
		memset(d2,INF,sizeof(d2));
		for(int i=1;i<=n;i++)d1[0][i][i]=d2[0][i][i]=0;
		while(m--)
		{
			scanf("%d%d%d",&u,&v,&w);
			d1[1][u][v]=min(d1[1][u][v],w);
		}
		dp();
		cin>>q;
		while(q--)
		{
			scanf("%d%d%d",&u,&v,&w);
			int ans=INF;
			for(int x=1;x<=n;x++)
				ans=min(ans,d2[w/100][u][x]+d1[w%100][x][v]);
			printf("%d\n",ans<INF?ans:-1);
		}
	}
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f

int T,n,m,q;
int d[51][51],d1[101][51][51],d2[101][51][51],d3[101][51][51];

void dp()
{
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

	for(int k=2;k<=100;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d1[k][i][j]=min(d1[k-1][i][x]+d1[1][x][j],d1[k][i][j]);
	
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			d2[1][i][j]=d1[100][i][j];
	for(int k=2;k<=100;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d2[k][i][j]=min(d2[k-1][i][x]+d2[1][x][j],d2[k][i][j]);

	for(int k=0;k<=100;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				for(int x=1;x<=n;x++)
					d3[k][i][j]=min(d3[k][i][j],d1[k][i][x]+d[x][j]);
}

int main()
{
	//freopen("input.in","r",stdin);
	cin>>T;
	while(T--)
	{
		int u,v,w;
		cin>>n>>m;
		memset(d,INF,sizeof(d));
		memset(d1,INF,sizeof(d1));
		memset(d2,INF,sizeof(d2));
		memset(d3,INF,sizeof(d3));
		for(int i=1;i<=n;i++)d[i][i]=d1[0][i][i]=d2[0][i][i]=0;
		while(m--)
		{
			scanf("%d%d%d",&u,&v,&w);
			d1[1][u][v]=min(d1[1][u][v],w);
			d[u][v]=min(d[u][v],w);
		}
		dp();
		cin>>q;
		while(q--)
		{
			scanf("%d%d%d",&u,&v,&w);
			int ans=INF;
			for(int x=1;x<=n;x++)
				ans=min(ans,d2[w/100][u][x]+d3[w%100][x][v]);
			printf("%d\n",ans<INF?ans:-1);
		}
	}
	return 0;
}