求解路径
【问题描述】
小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图
中的最短路径。
小蓝的图由 2021 个结点组成,依次编号 1 至 2021。
对于两个不同的结点 a, b,如果 a 和 b 的差的绝对值大于 21,则两个结点之间没有边相连;如果 a 和 b 的差的绝对值小于等于 21,则两个点之间有一条长度为 a 和 b 的最小公倍数的无向边相连。
例如:结点 1 和结点 23 之间没有边相连;结点 3 和结点 24 之间有一条无向边,长度为 24;结点 15 和结点 25 之间有一条无向边,长度为 75。
请计算,结点 1 和结点 2021 之间的最短路径长度是多少。
提示:建议使用计算机编程解决问题。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【代码】
- 考的时候题目没看,调代码调太久,现在做感觉能做出来,但可能要话较多时间。
/*
2021 21
10266837
*/
#include<iostream>
#include<cstring>
#include<cmath>
#define clr(x) memset(x,0,sizeof(x))
#define maxn 2021+5
using namespace std;
typedef unsigned long long ull;
const ull maxint=100000000000;
ull mp[maxn][maxn]; //存储邻接矩阵
int n=2021,m=21;
int arr[maxn][maxn];
int gcd(int a,int b) {
if(b>a) {
int t=a;
a=b;
b=t;
}
if(arr[a][b]) return arr[a][b];
while(a%b) {
int t=a%b;
a=b;
b=t;
}
arr[a][b]=b;
return b;
}
int lcm(int a,int b) {
int r=gcd(a,b);
return (a*b)/r;
}
//初始化邻接矩阵
void chushihua() {
clr(mp);
clr(arr);
for(int i=1; i<=n; i++)
for(int j=1; j<=i; j++)
if(abs(i-j)<=m) mp[i][j]=mp[j][i]=lcm(i,j);
else mp[i][j]=mp[j][i]=maxint;
}
ull Dis[maxn]; //距离
bool Set[maxn]; //已经确立距离的终点集
int Path[maxn]; //路径
ull ans=0;
void solve(int v1){
clr(Dis); clr(Set); clr(Path);
for(int i=1;i<=n;i++){
if(mp[v1][i]){
Dis[i]=mp[v1][i];
Path[i]=v1;
}else if(mp[v1][i]==0){
Dis[i]=maxint;
Path[i]=-1;
}
}
Set[v1]=1;
for(int i=2;i<=n;i++){
ull tmp=maxint;
for(int j=1;j<=n;j++){
if(!Set[j] && Dis[j]<tmp){
tmp=Dis[j];
v1=j;
}
}
// cout<<"v1="<<v1<<endl;
Set[v1]=1;
for(int j=1;j<=n;j++){
if(!Set[j] && mp[v1][j]+Dis[v1]<Dis[j]){
Dis[j]=mp[v1][j]+Dis[v1];
Path[j]=v1;
}
}
}
ans=Dis[n];
}
void show(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cout<<mp[i][j]<<" "; cout<<endl;
}
cout<<endl;
}
int main() {
cin>>n>>m; //2021 21
chushihua();
solve(1);
// show();
cout<<ans<<endl;
return 0;
}
2021-05-14 更新,感谢观看-