题意:有n个村庄,m个城堡,马里奥需要从n+m点的城堡回到1的村庄,同时,他有一双鞋每次使用可以连续飞行不超过L的距离,但是起点和终点必须是村庄或城堡,并且中间不能经过城堡,而且最多用k次,问他回到家的最短时间是多少。
思路:首先Floyd找出所有只以村庄作为中转点的每两个点间的最短距离,然后dp[u][k]表示到u点并且鞋子还可以用k次的最少花费时间。通过Dijkstra求得最后的答案。
AC代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
struct node
{
int u,k,cost;
bool operator<(const node a)const
{
return a.cost<cost;
}
};
int T,t,n,N,m,L,K,dp[110][11],dis[110][110],INF=1e9;
priority_queue<node> qu;
node a;
int Dijkstra()
{
while(!qu.empty())
qu.pop();
a.u=N;a.k=K;a.cost=0;
dp[N][K]=0;
qu.push(a);
int i,j,k,u,v,cost;
while(!qu.empty())
{
a=qu.top();
qu.pop();
u=a.u;
k=a.k;
cost=a.cost;
if(u==1)
return cost;
for(v=1;v<=N;v++)
{
if(dp[v][k]>dp[u][k]+dis[u][v])
{
dp[v][k]=dp[u][k]+dis[u][v];
a.u=v;
a.k=k;
a.cost=dp[v][k];
qu.push(a);
}
if(k>0 && dis[u][v]<=L && dp[v][k-1]>dp[u][k])
{
dp[v][k-1]=dp[u][k];
a.u=v;
a.k=k-1;
a.cost=dp[v][k-1];
qu.push(a);
}
}
}
}
int main()
{
int i,j,k,p,u,v,w,ans;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
scanf("%d%d%d%d%d",&n,&m,&k,&L,&K);
N=n+m;
for(i=1;i<=N;i++)
for(j=0;j<=K;j++)
dp[i][j]=INF;
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
dis[i][j]=INF;
for(i=1;i<=k;i++)
{
scanf("%d%d%d",&u,&v,&w);
dis[u][v]=dis[v][u]=w;
}
for(k=1;k<=n;k++)
for(i=1;i<=N;i++)
for(j=1;j<=N;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
ans=Dijkstra();
printf("%d\n",ans);
}
}