题意:
给出n个点,m条有向边,有q次询问,问从s到t至少经过条路的最短路为多少。其中。
思路:
dp也可以分块啊 感觉开拓了我的思路啊(๑•̀ㅂ•́)و✧真有趣!
这里有两份比较好的题解:
https://blog.csdn.net/weixin_42068627/article/details/81299321
https://blog.csdn.net/qq_34454069/article/details/81292814
首先考虑最朴素的dp,:从i到j至少走k条路的最短路。有转移:,其中表示i到j的最短路。
复杂度是,结合数据范围,这有。当然不可能是这么做的啦。
那么考虑倍增?
:从i到j恰好走条路的最短路。
:从i到j至少走条路的最短路。
有转移:
。
。
预处理的复杂度是,结合数据范围,这是,对于每次询问,枚举中转点i,,而这里的也需要二进制中的1也要循环处理,处理询问的复杂度为,结合数据范围,这是,似乎也不太行啊?
所以考虑分块。
假设分成M块,。
:从i到j恰好走k条路的最短路。
:从i到j至少走k条路的最短路。
:从i到j恰好走M*k条路的最短路。
有转移:
。
。
。
预处理的复杂度是,结合数据范围,这是,对于每个询问,枚举中转点l,,复杂度为,相比倍增,这个复杂度是可以接受的。
代码:
int g[55][55];
int d[55][55];
int dp[110][55][55];//从i到j恰好走k条路的最短路
int dp1[110][55][55];//从i到j至少走k条路的最短路
int dp2[110][55][55];//从i到j恰好走k*100条路的最短路
int main()
{
int t,n,m,x,y,z,q;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
memset(g,INF,sizeof(g));
for(int i=1;i<=n;i++)
g[i][i]=0;
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
g[x][y]=min(g[x][y],z);
}
/*for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",g[i][j]);
printf("\n");
}
printf("\n");*/
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=g[i][j];
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 i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",d[i][j]);
printf("\n");
}
printf("\n");*/
memset(dp,INF,sizeof(dp));
for(int i=1;i<=n;i++)
dp[0][i][i]=0;
for(int k=1;k<=100;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int l=1;l<=n;l++)
if(l!=j)dp[k][i][j]=min(dp[k][i][j],dp[k-1][i][l]+g[l][j]);
/*for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
printf("dp[%d][%d][%d]=%d\n",k,i,j,dp[k][i][j]);
printf("\n");*/
memset(dp1,INF,sizeof(dp1));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp1[0][i][j]=d[i][j];
for(int k=1;k<=100;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int l=1;l<=n;l++)
if(l!=j)dp1[k][i][j]=min(dp1[k][i][j],dp1[k-1][i][l]+d[l][j]);
/*for(int k=0;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
printf("dp[%d][%d][%d]=%d\n",k,i,j,dp1[k][i][j]);
printf("\n");*/
memset(dp2,INF,sizeof(dp2));
for(int i=1;i<=n;i++)
dp2[0][i][i]=0;
for(int k=1;k<=100;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int l=1;l<=n;l++)
dp2[k][i][j]=min(dp2[k][i][j],dp2[k-1][i][l]+dp[100][l][j]);
scanf("%d",&q);
while(q--)
{
scanf("%d%d%d",&x,&y,&z);
int p1=z/100,p2=z%100;
int ans=INF;
for(int l=1;l<=n;l++)
ans=min(ans,dp2[p1][x][l]+dp1[p2][l][y]);
if(ans==INF)printf("-1\n");
else printf("%d\n",ans);
}
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!