Description
给出一张无向图,问从1到n的最短路。
你可以瞬移k次,每次从u瞬移到v的条件是:u到v中存在一条不经过收费站的距离<=L的路径。当然,u或v可以是收费站。
收费站不会直接告诉你。而是给出p个提示,每个提示[x,y,z]表示编号在[x,y]这个区间中的点至少有z个收费站。
总共有m个收费站,保证唯一解。
m
Solution
首先解决收费站的问题。
把所有提示查分,那么就变成了pre[y]-pre[x-1]>=z。
还有其他一堆不等式。
那么便可以使用差分约束系统了。
接下来就直接预处理出所有点可以瞬移到的点,然后跑一边玄学算法sp(b)fa就好了。
因为有次数限制,就和GDOI2016Day2T1一样,用sp(b)fa来跑dp。
本蒟蒻这道题写了三个sp(b)faO(∩_∩)O~
Code
#include<cstdio>
#include<cstring>
#include<iostream>
#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 305
#define M 100005
using namespace std;
int n,m,e,p,Len,K,l,x,y,z,ans,d[M],g[M],dis[N],f[N][55];
int last[N],t[M],c[M],next[M],go[N][N],u[M],v[M],w[M];
bool bz[N],a[N],pd[N][55];
int get() {
char ch;while (!isdigit(ch=getchar()));
int o=ch-48;while (isdigit(ch=getchar())) o=o*10+ch-48;
return o;
}
void add(int x,int y,int z) {
t[++l]=y;c[l]=z;next[l]=last[x];last[x]=l;
}
int main() {
n=get();m=get();e=get();p=get();Len=get();K=get();
fo(i,1,e) u[i]=get(),v[i]=get(),w[i]=get();
fo(i,1,p) x=get(),y=get(),z=get(),add(x-1,y,z);
fo(i,0,n-1) add(i,i+1,0),add(i+1,i,-1);
add(0,n,m);add(n,0,-m);
memset(dis,128,sizeof(dis));dis[0]=0;
memset(bz,0,sizeof(bz));bz[0]=1;
int i=0,j=1;d[1]=0;
while (i<j) {
rep(k,d[++i]) if (dis[t[k]]<dis[d[i]]+c[k]) {
dis[t[k]]=dis[d[i]]+c[k];
if (!bz[t[k]]) bz[t[k]]=1,d[++j]=t[k];
}
bz[d[i]]=0;
}
fo(i,1,n) a[i]=dis[i]-dis[i-1];
memset(last,0,sizeof(last));l=0;
fo(i,1,e) add(u[i],v[i],w[i]),add(v[i],u[i],w[i]);
memset(bz,0,sizeof(bz));
fo(st,1,n) {
memset(dis,127,sizeof(dis));dis[st]=0;
int i=0,j=1;d[1]=st;bz[st]=1;
while (i<j) {
rep(k,d[++i]) if (dis[t[k]]>dis[d[i]]+c[k]) {
dis[t[k]]=dis[d[i]]+c[k];
if (!a[t[k]]&&!bz[t[k]]) bz[t[k]]=1,d[++j]=t[k];
}
bz[d[i]]=0;
}
fo(i,1,n) if (dis[i]<=Len&&i!=st) go[st][++go[st][0]]=i;
}
memset(f,127,sizeof(f));f[1][0]=0;
memset(pd,0,sizeof(pd));pd[1][0]=1;
i=0,j=1;d[1]=1;
while (i<j) {
int l=g[++i];
rep(k,d[i]) {
if (f[t[k]][l]>f[d[i]][l]+c[k]) {
f[t[k]][l]=f[d[i]][l]+c[k];
if (!pd[t[k]][l]) pd[t[k]][l]=1,d[++j]=t[k],g[j]=l;
}
}
if (l==K) {pd[d[i]][g[i]]=0;continue;}
fo(q,1,go[d[i]][0]) {
int x=go[d[i]][q];
if (f[x][l+1]>f[d[i]][l]) {
f[x][l+1]=f[d[i]][l];
if (!pd[x][l+1]) pd[x][l+1]=1,d[++j]=x,g[j]=l+1;
}
}
pd[d[i]][g[i]]=0;
}ans=0x7fffffff;
fo(i,0,K) ans=min(ans,f[n][i]);
printf("%d",ans);
}