题意:
n个城市,m个航班,你有k次免费坐航班的机会,问从s到t最少花费是多少?
题解:
分层图问题
简单说说什么是分层图:
其实就是将一个平面的图重新建图,有好几层
具体的说每层图之间各自连边与原图一样,但是相邻的两层图之间根据原来的关系进行连边
虽然是多层图,但是用一维的关系就可以
比如:
当有3个点,3层图时
1对应的就是 1+n 和 1+2 * n
2对应的就是 2+n 和 2+2 * n
…
当存在n个点,k层图时,
1对应的就是1+n * 0, 1+ n* 1…1+n * (k-1)
而且每一层的图都遵循只能从上面的图到下一层图,不能反过来
那建这么多层图的目的是什么呢?
你可以理解成是一种尝试,就比如本题,我们向下一层就代表拥有一次免费乘坐的机会,如果我们有k次免费乘坐机会,就建k层图(最原本的是第0层)。
每层图内部是原本的边权关系,而图与图之间是0边权(就相当于是免费乘坐机会)
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){
ll s=0,w=1ll;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
void rd_test(){
#ifdef ONLINE_JUDGE
#else
startTime = clock(); //计时开始
freopen("in.txt","r",stdin);
#endif
}
void Time_test(){
#ifdef ONLINE_JUDGE
#else
endTime = clock(); //计时结束
printf("\n运行时间为:%lfs\n",(double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=3e5+9;
struct node{
int w,now;
inline bool operator<(const node &x)const{
return w>x.w;
}
};
priority_queue<node>q;
int dis[maxn],vis[maxn];
vector<PII>vec[maxn];
int s,t;int n,m,k;
void dijkstra(){
memset(dis,INF_int,sizeof(dis));
dis[s]=0;
q.push((node){0,s});
while(!q.empty()){
node x=q.top();
q.pop();
int u=x.now;
if(vis[u])continue;
vis[u]=1;
for(auto it:vec[u]){
int v=it.first;
int w=it.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push({dis[v],v});
}
}
}
}
int main()
{
//rd_test();
cin>>n>>m>>k;
cin>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
vec[u].push_back({v,w});
vec[v].push_back({u,w});
for(int j=1;j<=k;j++){
//每一层
vec[u+j*n].push_back({v+j*n,w});
vec[v+j*n].push_back({u+j*n,w});
//层与层之间
vec[u+(j-1)*n].push_back({v+j*n,0});
vec[v+(j-1)*n].push_back({u+j*n,0});
}
}
dijkstra();
int minn=INF_int;
for(int i=0;i<=k;i++){
minn=min(minn,dis[t+i*n]);
}
cout<<minn;
return 0;
//Time_test();
}