题目链接:
题意:
一幅无向图有n1个村庄(1~n1),n2个城堡(n1~n1+n2),它们之间有m条边,马里奥知道每条边的距离且他1s能走1单位距离
马里奥要从1号村庄走到n1+n2号城堡,他有一双可以使用k次的跑鞋,每使用一次可以从一个地方迅速到达另一个地方,但中间不能经过城堡,且两个地方的距离不能超过L
问,马里奥最少需要多少时间
题解:
首先需要两个数组dis[i][j],ok[i][j]表示i到j的最短距离和能否用跑鞋从i到j
这两个数组都可以用floyed算法求得
最后从1->n1+n2 开始dp;
dp[i][j]表示k次以内到达i所需要的最小时间
k*n^2即可得到答案
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 105
#define INF 0x3f3f3f3f
using namespace std;
int dis[maxn][maxn],ok[maxn][maxn];
int dp[maxn][maxn];
int n,n1,n2,K,l;
void init()
{
n=n1+n2;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j]=i==j?0:INF;
memset(ok,0,sizeof(ok));
}
void floyed()
{
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
if(dis[i][j]>dis[i][k]+dis[k][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
if(k<=n1&&dis[i][j]<=l)
ok[i][j]=1;
}
}
}
void work()
{
int minn,temp;
for(int i=1; i<=n; i++)
dp[i][0]=dis[1][i];
for(int j=1; j<=K; j++)
dp[1][j]=0;
for(int i=2; i<=n; i++)
for(int j=1; j<=K; j++)
{
minn=INF;
for(int k=1; k<i; k++)
{
if(ok[k][i])
temp=min(dp[k][j-1],dp[k][j]+dis[k][i]);
else
temp=dp[k][j]+dis[k][i];
if(temp<minn)
minn=temp;
}
dp[i][j]=minn;
}
}
int main()
{
// freopen("in.txt","r",stdin);
int T,m,a,b,c;
for(scanf("%d",&T); T--;)
{
scanf("%d%d%d%d%d",&n1,&n2,&m,&l,&K);
init();
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
dis[a][b]=dis[b][a]=c;
if(c<=l)
ok[a][b]=ok[b][a]=1;
}
floyed();
work();
printf("%d\n",dp[n][K]);
}
}