解题思路:
本题的新颖之处在于建图的方法,建好图后就是一个简单的bfs或是Dijstra求最短路的问题。因为考虑到如果直接在原图中建立边的关系不太容易,所以我们想图中加入一些素数点,这些素数是原来所有的a[i]分解后得到的素数集合,为了防止与原来的a[i]重合,我们对这些素数统一加n处理这样的话,我们还按照题中的规则建图,那么只要gcd(x,y)!=1,那么x和y一定能通过一个素数连接且素数之间互不连接,这样在原图中求得的距离再除以2就是本来的距离。
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
vector<int>G[2*N];
int a[N];
int n,s,t;
struct NODE{
int id;
int dis;
friend bool operator <(const NODE&x,const NODE&y)
{
return x.dis>y.dis;
}
};
priority_queue<NODE>pq;
int d[2*N];
int pre[2*N];
const int INF=0x3f3f3f3f;
void add(int x,int y)
{
G[x].push_back(y);
G[y].push_back(x);
return;
}
void Dijstra()
{
for(int i=0;i<2*N;i++)d[i]=INF;
d[s]=0;
pq.push({s,0});
while(!pq.empty()){
NODE u=pq.top();
pq.pop();
for(int i:G[u.id]){
if(d[i]>d[u.id]+1){
d[i]=d[u.id]+1;
pre[i]=u.id;
pq.push({i,d[i]});
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
scanf("%d %d",&s,&t);
//接下来是建图环节,其实也是找素因子的环节
for(int i=1;i<=n;i++){
//这里用到了一个小的结论即i的所有素因子中最多有一个大于根号下i的
for(int j=2;j*j<=a[i];j++){
//j这里可以直接加加,是因为可以确保最终与i相连的一i的一定是一个素数,如果是一个合数,那么
//这个合数一定可以分解为若干个比它小的素数,而这些素因子再之前就已经处理掉了,矛盾
if(a[i]%j==0){
add(i,j+N);//建边(无向边)
}
while(a[i]%j==0)a[i]/=j;//这步的目的是确保消除掉a[i]中所有的j素因子
}
if(a[i]>1){
add(i,a[i]+N);//这里就是可能出现的唯一一个大于根号下i的素因子
}
}
//接下来是求最短路的环节
Dijstra();
if(d[t]==INF){
printf("-1\n");
}
else{
printf("%d\n",d[t]/2+1);
vector<int>ans;
for(int i=t;i!=s;i=pre[i]){
ans.push_back(i);
}
ans.push_back(s);
for(int i=ans.size()-1;i>=0;i-=2)printf("%d ",ans[i]);
}
return 0;
}