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.
Input
The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.
In each test case, there are 2 integers n,m(2≤n≤50,1≤m≤10000)
in the first line, denoting the number of intersections and one way streets.
In the next m lines, each line contains 3 integers ui,vi,wi(1≤ui,vi≤n,ui≠vi,
1≤wi≤10000), denoting a one way street from the intersection ui to vi, and the length of it is wi
Then in the next line, there is an integer q(1≤q≤100000) , denoting the number of days. In the next q lines, each line contains 3 integers si,ti,ki(1≤si,ti≤n,1≤ki≤10000) , describing the walking plan.
Output
For each walking plan, print a single line containing an integer, denoting the minimum total walking length. If there is no solution, please print -1.
Examples
Input
2
3 3
1 2 1
2 3 10
3 1 100
3
1 1 1
1 2 1
1 3 1
2 1
1 2 1
1
2 1 1
Output
111
1
11
-1
【题目链接】 Walking Plan
【题意】
给定一个 n个点,m条边的有向图,q 次询问 s 到 t 经过至少 k 条边的最短路。
【思路】
用c[i][j]表示从i经过一条边到j的最短路,a[path][i][j]表示从i恰好经过path条边到j的最短路
那么有转移方程a[path][i][j]=min{a[path-1][i][k]+c[k][j]}
这个转移方程是n3的,k的范围有10000,所以不能直接转移,我们考虑把每个询问s,t,k拆成两部分:
从 s 出发经过恰好 100A 条边到达某个点 u。
从 u 出发经过至少 B 条边到达 t。
然后我们再用a[path][i][j]表示从i恰好经过path*100条边到j的最短路
由于题目要求最少k条边,我们再对b数组跑一次Floyd算法即可
然后令A=k%100,B=k/100,枚举中间点u,答案就是min{a[A][s][u] +b[B][u][t]}。
有点人可能会问,为什么不用对a数组跑Floyd,因为我们b[0][i][j]储存的就是i到j的最短路,我们可以先恰好A步到某一个点,然后走最短路到终点即可,也是大于等于k的
#include <cstdio>
#include <bits/stdc++.h>
#include <cmath>
#include <map>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 55;
const ll mod = 1e9+7;
const int INF = 1e9;
const double eps = 1e-6;
int n,m,q;
int c[maxn][maxn];
int dis[maxn][maxn];
int tmp[maxn][maxn];
int a[105][maxn][maxn];
int b[105][maxn][maxn];
void solve(int a[][maxn],int b[][maxn],int c[][maxn])
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
c[i][j]=INF;
for(int k=0;k<n;k++)
{
c[i][j]=min(c[i][j],a[i][k]+b[k][j]);
}
}
}
void Floyd()
{
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
int main()
{
rush()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
c[i][j]=INF;
a[0][i][j]=b[0][i][j]=(i==j?0:INF);
}
while(m--)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u--,v--;
c[u][v]=min(c[u][v],w);
}
for(int i=1;i<105;i++) solve(a[i-1],c,a[i]);
for(int i=1;i<105;i++) solve(b[i-1],a[100],b[i]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
dis[i][j]=(i==j?0:c[i][j]);
}
Floyd();
for(int path=0;path<105;path++)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
tmp[i][j]=INF;
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
{
tmp[i][j]=min(tmp[i][j],b[path][i][k]+dis[k][j]);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
b[path][i][j]=tmp[i][j];
//if(path==0) printf("%d %d**%d\n",i+1,j+1,tmp[i][j]);
}
}
scanf("%d",&q);
while(q--)
{
int u,v,k;
scanf("%d%d%d",&u,&v,&k);
u--,v--;
int A=k%100,B=k/100;
int ans=INF;
for(int i=0;i<n;i++)
{
ans=min(ans,a[A][u][i]+b[B][i][v]);
}
if(ans==INF) puts("-1");
else printf("%d\n",ans);
}
}
}