题目链接: hdu 4396
题目大意: 给出带权值的无向边,可能会有自环
给出起点和终点,求至少经过K条边的最短路径
解题思路: 当k不能被10整除时,K=k%10+1,否则K=k%10;
二维SPFA,Dp[ a ][ b ]表示经过b条边到达a点的最短路径
剪枝的地方是把b>K的看成b=K,因为b>=K的都是满足题意的答案
把b>K并入b=K,省去无用的搜素,降低时间复杂度
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 5010
#define INF 0x3f3f3f3f
int Dp[MAX][505],pre[MAX],Index,visit[MAX][505];
struct snode{
int to,w,next;
}Edge[210000];
struct node{
int v,len;
}listb[2000000],v1,v2;
void Add_edge(int a,int b,int c)
{
Edge[Index].to=b; Edge[Index].w=c;
Edge[Index].next=pre[a];
pre[a]=Index++;
}
int SPFA(int a,int b,int c)
{
int s,e,i,vv,vlen;
memset(visit,0,sizeof(visit));
s=e=0;
Dp[a][0]=0;
v1.len=0,v1.v=a;
listb[s++]=v1;
while(s!=e)
{
v1=listb[e++];
visit[v1.v][v1.len]=0;
for(i=pre[v1.v];i!=-1;i=Edge[i].next)
{
vlen=v1.len+1;
if(vlen>=c) //把 len>K的看成K
vlen=c;
vv=Edge[i].to;
if(Dp[vv][vlen]>Dp[v1.v][v1.len]+Edge[i].w)
{
Dp[vv][vlen]=Dp[v1.v][v1.len]+Edge[i].w; //更新
if(!visit[vv][vlen]) //防止重复人队列
{
v2.v=vv,v2.len=vlen;
visit[vv][vlen]=1;
listb[s++]=v2;
}
}
}
}
return Dp[b][c];
}
int main()
{
int i,j,n,m,a,b,c,t;
while(scanf("%d%d",&n,&m)!=EOF)
{
Index=0;
memset(pre,-1,sizeof(pre));
memset(Dp,INF,sizeof(Dp));
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
Add_edge(a,b,c);
Add_edge(b,a,c);
}
scanf("%d%d%d",&a,&b,&c);
t=c;
c/=10;
if(t%10!=0) //至少为c分,既>=c
c++;
t=SPFA(a,b,c);
if(t==INF)
printf("-1\n");
else
printf("%d\n",t);
}
return 0;
}