分层最短路用更加具体或者形象一点的说法就是有限制的最短路径问题。
通常是拆点解决问题,原图中的点加上一个当前点的状态,成为一个新的点
P4568 [JLOI2011] 飞行路线
#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
void solve()
{
int n,m,k;
cin>>n>>m>>k;
int s,t;
cin>>s>>t;
vector<vector<pii>>g(n+1);
rep(i,1,m){
int u,v,w;
cin>>u>>v>>w;
//无向图,建双向边
g[u].pb({v,w});
g[v].pb({u,w});
}
struct node{
int val,u,cnt;
//大根堆只能重载小于号,小根堆只能重载大于号
bool operator<(const node&t)const{
return val>t.val;
}
};
priority_queue<node>q;
vector<vector<int>>d(n+1,vector<int>(k+1,0x3f3f3f3f));
vector<vector<int>>vis(n+1,vector<int>(k+1));
d[s][0]=0;
q.push({0,s,0});
while(q.size()){
auto t=q.top();
q.pop();
int val=t.val,u=t.u,cnt=t.cnt;
if(vis[u][cnt]) continue;
vis[u][cnt]=1;
for(auto it:g[u]){
int v=it.x,w=it.y;
//不用免费的机会
if(d[v][cnt]>d[u][cnt]+w){
d[v][cnt]=d[u][cnt]+w;
q.push({d[v][cnt],v,cnt});
}
//用免费的机会
if(cnt<k&&d[v][cnt+1]>d[u][cnt]){
d[v][cnt+1]=d[u][cnt];
q.push({d[v][cnt+1],v,cnt+1});
}
}
}
int res=0x3f3f3f3f*1ll;
rep(i,0,k){
res=min(res,d[t][i]);
}
cout<<res<<endl;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
// cin>>_;
// while(_--)
solve();
return 0;
}
图论真难qwq
这道题目也可以用分层图的思想,或者dp的思想去解决
分层图并不一定要把图建出来,只需要进行拆点。
对于这类有选择会导致不同结果的可以通过拆点来解决
把原图上的点加上到达该点时的状态结合产生新的点。
这道题目和最短路的转移也不一样了,与其说是最短路但是感觉更像是用队列去写的dp,因为题目中并没有说是
D
A
G
DAG
DAG
d
[
u
]
[
c
n
t
]
:
表示到达
u
点前面已经用过
c
n
t
次的最大边权
d[u][cnt]:表示到达u点前面已经用过cnt次的最大边权
d[u][cnt]:表示到达u点前面已经用过cnt次的最大边权
转移:考虑使用和不使用
不使用
//不用这次免费的边
if(max(d[u][cnt],w)<d[v][cnt]){
d[v][cnt]=max(d[u][cnt],w);
if(!inq[v][cnt]){
q.push({v,cnt});
inq[v][cnt]=1;
}
使用:需要还有次数才能使用
//使用
if(cnt<k&&d[u][cnt]<d[v][cnt+1]){
d[v][cnt+1]=d[u][cnt];
if(!inq[v][cnt+1]){
q.push({v,cnt+1});
inq[v][cnt+1]=1;
}
}
#include <bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define fep(i,a,b) for(int i = (a); i >= (b); --i)
#define pii pair<int, int>
#define ll long long
#define db double
#define endl '\n'
#define x first
#define y second
#define pb push_back
#define inf 0x3f3f3f3f*1ll
using namespace std;
void solve()
{
int n,m,k;
cin>>n>>m>>k;
vector<vector<pii>>g(n+1);
rep(i,1,m){
int u,v,w;
cin>>u>>v>>w;
g[u].pb({v,w});
g[v].pb({u,w});
}
vector<vector<int>>inq(n+1,vector<int>(k+1,0));
vector<vector<int>>d(n+1,vector<int>(k+1,0x3f3f3f3f));
queue<pii>q;
d[1][0]=0;
inq[1][0]=1;
q.push({1,0});
//跑一遍最短路
while(q.size()){
auto t=q.front();
q.pop();
int u=t.x,cnt=t.y;
inq[u][cnt]=0;
for(auto it:g[u]){
int v=it.x,w=it.y;
//不用这次免费的边
if(max(d[u][cnt],w)<d[v][cnt]){
d[v][cnt]=max(d[u][cnt],w);
if(!inq[v][cnt]){
q.push({v,cnt});
inq[v][cnt]=1;
}
}
//使用
if(cnt<k&&d[u][cnt]<d[v][cnt+1]){
d[v][cnt+1]=d[u][cnt];
if(!inq[v][cnt+1]){
q.push({v,cnt+1});
inq[v][cnt+1]=1;
}
}
}
}
int res=inf;
rep(i,0,k){
res=min(res,d[n][i]);
}
cout<<(res==inf?-1:res)<<endl;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
// freopen("1.in", "r", stdin);
int _;
// cin>>_;
// while(_--)
solve();
return 0;
}