Description
给出一张n个点,m条边的有向图。若A->B有一条边,B->C有一条边,则可以使用L的时间直接从A到C。总共只可以走lim次这样的近路。求1到n的最短路。若无解,输出-1。
n<=10000,m<=50000,lim<=5
Solution
加了一点点东西的最短路。
迪杰斯特拉有点麻烦,就直接打玄学算法sp(b)fa。
多开一维j,维护1到当前这个点走了j次近路的最短路。
出题人良心没有卡O(∩_∩)O
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
#define N 10005
#define M 50005
using namespace std;
int n,m,l,x,y,z,L,lim,dis[N][6],d[M*5];
int last[N],next[M],t[M],v[M];
bool bz[N];
void add(int x,int y,int z) {
t[++l]=y;v[l]=z;next[l]=last[x];last[x]=l;
}
int main() {
freopen("sigemago.in","r",stdin);
freopen("sigemago.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&L,&lim);
fo(i,1,m) scanf("%d%d%d",&x,&y,&z),add(x,y,z);
memset(dis,127,sizeof(dis));int mx=dis[0][0];fo(i,0,lim) dis[1][i]=0;
int i=0,j=1;d[1]=1;bz[1]=1;
while (i<j) {
rep(k,d[++i])
fo(l,0,lim) {
if (dis[t[k]][l]>dis[d[i]][l]+v[k]) {
dis[t[k]][l]=dis[d[i]][l]+v[k];
if (!bz[t[k]]) bz[t[k]]=1,d[++j]=t[k];
}
if (l==lim) continue;
rep(p,t[k]) if (dis[t[p]][l+1]>dis[d[i]][l]+L) {
dis[t[p]][l+1]=dis[d[i]][l]+L;
if (!bz[t[p]]) bz[t[p]]=1,d[++j]=t[p];
}
}
bz[d[i]]=0;
}
if (dis[n][lim]!=mx) printf("%d",dis[n][lim]);
else printf("-1");
}