[JLOI2011]飞行路线
【题面】:
飞行路线
【思路】:
初看此题是不是有点懵逼.jpg啊。。(反正我就是)
首先最短路\(spfa\)的做法还是比较明显,但是本题要求他还可以免费搭乘\(k\)次航线,然而\(k\)很小(\(k\leq10\)),可以当作\(dp\)的一维来处理。那么就可以考虑\(dp\)。
我们用\(dis[i][j]\)表示从起点到\(i\)的最小花费,那么易得\(dis[i][0]\)就是最短路的花费,其余的情况通过枚举\(k\)来得到。
- \(dp[v][0] = min(dp[v][0] , dp[u][0] + dis[u,v])\)
- \(dp[v][k] = min(dp[v][k] , dp[u][k]+dis[u,v] , dp[u][k-1])\)
我觉得还是好理解就不给注释了。。
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k;int s,t;
const int MAXN = 10005;
const int MAXM = 50005;
struct edge{
int u,v,w,nxt;
}e[MAXM<<1];int head[MAXN];int cnt=0;bool r[MAXN];
int dis[MAXN][15];//表示从s到i这个点使用j次技能的最短路
//dp[v][j] = max(dp[u][j]+dis(u,v) , dp[u][j-1])
inline void add(int u,int v,int w){
e[++cnt].u = u;e[cnt].v = v;e[cnt].w = w;e[cnt].nxt = head[u];head[u] = cnt;
}
queue<int>q;
inline void spfa(){
q.push(s);memset(dis,inf,sizeof dis);
for(int i=0;i<=k;++i) dis[s][i] = 0;
while(!q.empty()){
int u = q.front();q.pop();r[u] = 0;
for(int i=head[u];~i;i=e[i].nxt){
int v = e[i].v;
if(dis[u][0] + e[i].w < dis[v][0]){
dis[v][0] = dis[u][0] + e[i].w;
if(!r[v]){
r[v] = 1;
q.push(v);
}
}
for(int j=1;j<=k;++j){
dis[v][j] = min(dis[u][j-1] , min(dis[u][j]+e[i].w , dis[v][j]));
}
}
}
int ans = inf;
for(int i=0;i<=k;++i) ans = min(ans , dis[t][i]);
printf("%d\n",ans);
}
int main(){
scanf("%d%d%d",&n,&m,&k);
scanf("%d%d",&s,&t);
memset(head,-1,sizeof head);
for(int i=1;i<=m;++i){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
spfa();
return 0;
}
然鹅这个只有\(90dpts\),你还要一个\(SLF\)优化(大雾
#include<cstdio>
#include<queue>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
int n,m,k;int s,t;
const int MAXM = 50005;
const int MAXN = 10005;
inline ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
struct edge{
int u,v,w,nxt;
}e[MAXM<<1];int head[MAXN];int cnt=0;int dis[MAXN][15];int used[MAXN];int r[MAXN];
inline void add(int u,int v,int w){
e[++cnt].u = u;e[cnt].v = v;e[cnt].w = w;e[cnt].nxt = head[u];head[u] = cnt;
}
struct node{
int p,used;
node():p(0),used(0){}
node(int a,int b):p(a),used(b){}
};
deque<node>q;
inline void spfa(int x){
memset(dis,inf,sizeof dis);
for(int i=0;i<=k;++i) dis[x][i] = 0;
q.push_back(node(x,0));
while(!q.empty()){
node u = q.front();q.pop_front();
for(int i=head[u.p];i;i=e[i].nxt){
int v = e[i].v;
if(dis[v][u.used] > dis[u.p][u.used] + e[i].w){
dis[v][u.used] = dis[u.p][u.used] + e[i].w;
if(!q.empty() && dis[v][u.used] < dis[q.front().p][u.used]) q.push_front(node(v,u.used));else q.push_back(node(v,u.used));
}
if(u.used+1 <= k && dis[v][u.used+1] > dis[u.p][u.used]){
dis[v][u.used+1] = dis[u.p][u.used];
if(!q.empty() && dis[v][u.used+1] < dis[q.front().p][u.used]) q.push_front(node(v,u.used+1));else q.push_back(node(v,u.used+1));
}
}
}
}
int main(){
n=read();m=read();k=read();
s = read();t = read();s++;t++;
for(int i=1;i<=m;++i){
int u,v,w;u = read();v = read();w = read();
u++;v++;
add(u,v,w);add(v,u,w);
}
spfa(s);
int ans = inf;
for(int i=0;i<=k;++i) ans = min(ans , dis[t][i]);
printf("%d",ans);
return 0;
}