AcWing
算法:spfa的分层图
和拯救大兵瑞恩差不多(我的另一篇分层图的博客)
d i s [ u ] [ i ] dis[u][i] dis[u][i]表示到 u u u这个节点已经用了 i i i次免费机会了
可以考虑动归的思考方式( v v v是 u u u的下一个点)
- 如果这条路不免费 d i s [ v ] [ i ] = m a x ( d i s [ u ] [ i ] , e [ i ] . w ) dis[v][i]=max(dis[u][i],e[i].w) dis[v][i]=max(dis[u][i],e[i].w)
- 如果这条路免费 d i s [ v ] [ i ] = d i s [ u ] [ i − 1 ] dis[v][i]=dis[u][i-1] dis[v][i]=dis[u][i−1]
所有关于边的条件或者性质,其实都可以认为是一种特殊边.
这道题目中,有些边可以代价为0,那么我们不妨设置一种特殊边.
比如说 ( a , b ) (a,b) (a,b)是相连的边,他们代价是 c c c,那么如果说我们让它免费,不就是又多了一条边, ( a ′ , b ′ ) (a',b') (a′,b′),只不过他们的代价是0
所谓的路径可以免费,就是多了一条为0的重边.
所以这道题目的性质,转换一下就是,我们可以设置K条为权值0的边.
#include<bits/stdc++.h>
#include<queue>
#define ll long long
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
#define don(i,a,b) for(register int (i)=(a);(i)>=(b);(i)--)
using namespace std;
const int maxn=1e6+10;
const int maxm=1e3+10;
int n,m,cnt,k;
int head[maxn],dis[maxm][maxm],vis[maxm];
template <class t> inline void read(t &x)
{
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
x*=f;
}
struct node{
int v,nex,w;
}e[maxn<<1];
void add(int u,int v,int w) {
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
void readdata() {
read(n),read(m),read(k);
rep(i,1,m) {
int x,y,z;
read(x),read(y),read(z);
add(x,y,z);add(y,x,z);
}
}
void spfa()
{
queue<int > q;
memset(dis,0x3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[1][0]=0;
vis[1]=1;
q.push(1);
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for (int i=head[x];i;i=e[i].nex) {
int j=e[i].v,z=e[i].w,w=max(dis[x][0],z);
if(dis[j][0]>w) {
dis[j][0]=w;
if(!vis[j])
q.push(j),vis[j]=1;
}
for(int p=1; p<=k; p++) {
int w=min(dis[x][p-1],max(dis[x][p],z));
if (dis[j][p]>w) {
dis[j][p]=w;
if(!vis[j])
q.push(j),vis[j]=1;
}
}
}
}
}
void work() {
spfa();
int ans=0x3f3f3f3f;
rep(i,0,k) {
if(ans>dis[n][i])
ans=dis[n][i];
}
if(ans==0x3f3f3f3f) {
printf("-1");
}
else printf("%d\n",ans);
}
int main() {
//freopen("input.txt","r",stdin);
readdata();
work();
return 0;
}