ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

1031 Rinne Loves Graph 求经过k个障碍到达n的最短路 分层图或最短路+dp

2022-08-23 17:01:19  阅读:160  来源: 互联网

标签:tmp 10 Rinne idx int 短路 add 1031 dis


 链接:https://ac.nowcoder.com/acm/contest/26077/1031
来源:牛客网

题目描述

Island 发生了一场暴乱!现在 Rinne 要和 Setsuna 立马到地上世界去。
众所周知:Island 是有一些奇怪的城镇和道路构成的(题目需要,游戏党勿喷),有些城镇之间用双向道路连接起来了,且每条道路有它自己的距离。但是有一些城镇已经被派兵戒严,虽然主角可以逆天改命强闯,但是为了体验该游戏的平衡性,他们只能穿过不超过 K 次被戒严的城镇。 定义“穿过”:从一个戒严的点出发到达任意一个点,都会使得次数加1 现在他们想从 1 号城镇最快的走到 n 号城镇(即出口),现在他们想让你告诉他们最短需要走多少路。

输入描述:

第一行三个整数 n,m,k,分别表示城镇数量,边数量和最多能闯过被戒严的城市的次数。
接下来 n 行,每行一个整数 1 或 0,如果为 1 则表示该城市已被戒严,0 则表示相反。
接下来 m 行,每行三个数 u,v,w,表示在 u 城镇和 v 城镇之间有一条长度为 w 的双向道路。

输出描述:

输出一行一个数字,表示从 1 到 n 的最短路径,如果到达不了的话,请输出 -1。
示例1

输入

复制
4 5 1
1
0
1
0
1 2 10
2 3 10
3 1 15
1 4 60
3 4 30

输出

复制
60

备注:

2≤n≤800,1≤m≤4000,1≤k≤10,1≤w≤1062 \leq n \leq 800,1 \leq m \leq 4000,1 \leq k \leq 10,1 \leq w \leq 10^62≤n≤800,1≤m≤4000,1≤k≤10,1≤w≤106
保证没有多条道路连接同一对城市,也没有一条道路连向自己。

分析

1.分层图

为每对节点在每一层 建立一条边

1.如果当前节点没有阻塞,就可以直接走到同层另一个节点

2.如果当前节点有阻塞,就需要从当前节点走到下一层的另一个节点

 

跑最短路

在 给定层数里,取 其中 可以到达终点的层 到达终点的最短路

 

//-------------------------代码----------------------------

#define int ll
const int N = 2e6+10;
int n,m,k;
int e[N],ne[N],w[N],h[N],idx;
int a[N];
int dis[N];
void add(int a,int b,int c) {e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++ ;}
bool vis[N];

void dij() {
    ms(dis,inf);dis[1] = 0;
    priority_queue<pii,V<pii>,greater<pii>> q;
    q.push({0,1});
    while(q.size()) {
        auto tmp = q.top();q.pop();
        if(vis[tmp.second]) continue;
        vis[tmp.second] = 1;
        for(int i = h[tmp.second];~i;i=ne[i]) {
            int j = e[i];
            if(dis[j] > w[i] + tmp.x) {
                dis[j] = w[i] + tmp.x;
                q.push({dis[j],j});
            }
        }
    }
}

void solve() {
    cin>>n>>m>>k;
    ms(h,-1);
    fo(i,1,n) cin>>a[i];
    fo(i,1,m) {
        int x,y,z;cin>>x>>y>>z;
        if(!a[x]) {
            fo(j,0,k) add(x + n * j,y + n * j,z);//当前层
        }
        if(!a[y]) {
            fo(j,0,k) add(y + n * j,x + n * j,z);
        }
        if(a[x]) {
            fo(j,0,k-1) add(x + n * j,y + n * (j+1),z);
        }
        if(a[y]) {
            fo(j,0,k-1) add(y + n * j,x + n * (j+1),z);
        }
    }
    if(k < 0) {None;rt;}
    dij();
    int ans = inf;
    fo(i,1,k+1) ans = min(ans,dis[i*n]);
    if(ans == inf) ans = -1;
    cout<<ans<<endl;
}

void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

2.最短路+DP

分析

线性DP是到了某个点 j ,就从前面的点 i 更新过来

这题随着点数的增加,k 会逐渐变大,路程会逐渐变大,当前枚举到的点会变化

所以设状态为 dp [i][ k] 表示当前枚举到 j 点,已经经历了 k 个障碍

由于要跑 到点 n 的最小路径,所以跑dijkstra

当枚举到新的点,更新当前的 k 就可以一路跑到 n 点了。

//-------------------------代码----------------------------

//#define int ll
const int N = 1e5+10;
int n,m,k;
int e[N],h[N],w[N],ne[N],idx;
int dis[N][15];
void add(int a,int b,int c) {
    e[idx] = b,ne[idx] = h[a],w[idx] = c,h[a] = idx ++ ;
}
struct node {
    int id,c,k;
    bool operator<(const node & x) const {
        return c > x.c;
    }
};

int a[N];
bool vis[N];

void dij() {
    ms(dis,inf);
    dis[1][0] = 0;
    priority_queue<node> q;
    q.push({1,0,0});
    while(q.size()) {
        auto tmp = q.top();q.pop();;
        if(vis[tmp.id]) continue;
        vis[tmp.id] = 1;
        for(int i = h[tmp.id];~i;i=ne[i]) {
            int j = e[i];int nowk = a[tmp.id] + tmp.k;
            if(nowk > k) continue;
            if(dis[j][nowk] > w[i] + tmp.c) {
                dis[j][nowk] = w[i] + tmp.c;
                q.push({j,dis[j][nowk],nowk});
            }
        }
    }
}

void solve()
{

    cin>>n>>m>>k;
    for(int i = 1; i<=n; i++) cin>>a[i];
    ms(h,-1);
    for(int x,y,w,i = 1; i<=m; i++) {
        cin>>x>>y>>w;
        add(x,y,w);
        add(y,x,w);
    }
    dij();
    int ans = INF;
    for(int i=0; i<=k; i++) {
        ans=min(ans,dis[n][i]);
    }
    if(ans==INF) puts("-1");
    else printf("%d\n",ans);
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:tmp,10,Rinne,idx,int,短路,add,1031,dis
来源: https://www.cnblogs.com/er007/p/16616937.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有