题目梗概
给出一个有
m
条边(有边权)
给出
Q
个询问
解题思路
因为有边权递增的限制,不难想到把所以边排序之后一条条插入。
考虑一个数组
f[i][j][k]
表示从
i
到
以每个节点为起点来考虑这个问题,再考虑插入了一条边,显然需要修正
新姿势
一个多维的量,比如上述DP的 f[i][j][k] ,当我们访问地址的时候显然需要做两次乘法和一次加法,如果我们提前开指针指向 f[i][j] ,那么只需要做一次加法,事实证明使用这个写法可以得到显著的优化。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int maxm=5005,maxn=155;
struct jz{
int x,y,w;
bool operator<(const jz&b)const{return w<b.w;}
}a[maxm];
int n,m,Q,f[maxn][maxn][maxn],t;
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
scanf("%d",&t);
while (t--){
scanf("%d%d%d",&n,&m,&Q);
for (int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
sort(a+1,a+1+m);
memset(f,63,sizeof(f));
for (int i=1;i<=n;i++) f[i][i][0]=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
int *f1=f[i][a[j].x],*f2=f[i][a[j].y];
for (int k=1;k<=n;k++) f2[k]=min(f2[k],f1[k-1]+a[j].w);
}
while (Q--){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
int ans=f[0][0][0];z=min(z,n);
for (int i=0;i<=z;i++) ans=min(ans,f[x][y][i]);
if (ans==f[0][0][0]) printf("-1\n");else printf("%d\n",ans);
}
}
return 0;
}