[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;
}

转载于:https://www.cnblogs.com/lajioj/p/9562650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值