炫酷路途(2019牛客寒假算法基础集训营 Day5-D)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011815404/article/details/86763089

【题目描述】

小希现在要从寝室赶到机房,路途可以按距离分为N段,第i个和i+1个是直接相连的,只需要一秒钟就可以相互到达。

炫酷的是,从第i个到第i+2p个也是直接相连的(其中p为任意非负整数),只需要一秒钟就可以相互到达。

更炫酷的是,有K个传送法阵使得某些u,v之间也是直接相连的,只需要一秒钟就可以相互到达,当然,由于设备故障,可能会有一些u=v的情况发生。

现在小希为了赶路,她需要在最短的时间里从寝室(编号为1)到达机房(编号为N),她不希望到达这N个部分以外的地方(不能到达位置N+1),也不能走到比自己当前位置编号小的地方(比如从5走到3是非法的)。

她想知道最短的时间是多少。

【输入描述】

第一行输入两个整数N,K,表示路途的段数和传送法阵的数量。

从第二行开始K行,每行两个整数ai,bi表示两个位置之间相连。

2≤N≤1,000,000,000
0≤K≤15

【输出描述】

输出一个整数,表示从寝室到机房最短的时间是多少秒。

【样例】

示例1

输入
12 2
1 5
6 6
输出
3

示例2

输入
17 2
2 5
8 9
输出
1

思路:

n 很大很吓人但其实影响不大,实际上将所有额外连边的 k*2 个点再加上起点、终点就可以构成一张图,最多只有 32 个点,然后计算两点间的距离求最短路即可

【源代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-6
#define INF 0x3f3f3f3f
#define N 3001
#define LL long long
const int MOD=1e9+7;
using namespace std;
int n,m;
struct Edge{
    int x,y;
}edge[N];
struct Node{
    int x,w;
    Node(){}
    Node(int x,int w):x(x),w(w){}
    bool operator < (const Node &rhs)const{
        return w>rhs.w;
    }
};
vector<int> mp;//图
int G[N][N];//边权
int res[N];
bool vis[N];
int bit(int x){//计算x中1的个数
    int cnt=0;
    while(x){
        if(x&1)
            cnt++;
        x>>=1;
    }
    return cnt;
}
int calculate(int x){//计算图中第一个大于等于x的位置
    return lower_bound(mp.begin(),mp.end(),x)-mp.begin();
}
void dijkstra(){
    memset(res,INF,sizeof(res));
    res[0]=0;

    priority_queue<Node> Q;
    Q.push(Node(0,0));

    while(!Q.empty()){
        int x=Q.top().x;
        int w=Q.top().w;
        Q.pop();

        vis[x]=true;
        for(int y=0;y<mp.size();y++){
            if(!vis[y]&&w+G[x][y]<res[y]){
                res[y]=w+G[x][y];
                Q.push(Node(y,res[y]));
            }
        }
    }
}
int main(){
    cin>>n>>m;

    int cnt=0;
    for(int i=0;i<m;i++){
        int x,y;
        cin>>x>>y;
        if(x!=y&&x<=n&&y<=n){
            if(x>y)//序号小者在前,保证边是有向的
                swap(x,y);
            //存点
            mp.push_back(x);
            mp.push_back(y);
            //存边
            edge[cnt].x=x;
            edge[cnt].y=y;
            cnt++;
        }
    }

    mp.push_back(1);//起点
    mp.push_back(n);//终点

    sort(mp.begin(),mp.end());
    mp.erase(unique(mp.begin(),mp.end()),mp.end());//去重

    //计算边权
    memset(G,INF,sizeof(G));
    for(int i=0;i<mp.size();i++)
        for(int j=i+1;j<mp.size();j++)
            G[i][j]=min(G[i][j],bit(mp[j]-mp[i]));
    for(int i=0;i<cnt;i++)
        G[calculate(edge[i].x)][calculate(edge[i].y)]=min(G[calculate(edge[i].x)][calculate(edge[i].y)],1);

    dijkstra();

    cout<<res[mp.size()-1]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/86763089