版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}