第一个问题,使用memset()函数必须加上 #include<cstring>, 否则 sicily编译失败;第二个问题,题目没有说明开始的数字就一定比结束的数字小,看到例子我就想当然了!
最后,为了能提高小小的效率,还是要每步都判断一下,剪枝;
思路:从起点开始,找出当改变一位能获取到的“素数”,判断是否已寻找到了,若是则结束;否则,将其推入队列中;从队列中的头部开始遍历,逐渐改变每一位,获取下一个能获得的“素数”
#include<iostream>
#include<queue>
#include<cstring>//没加这个sicily编译不过(memset)
using namespace std;
/*用于标记从0开始到9999是否被访问过了*/
bool visited[10000];
/*将非素数的访问设置为已访问,即不再去访问非素数*/
void RejectNotPrime()
{
visited[1] = 1;
for(int i = 2; i <= 100; i++)
{
for(int j = i; j <= 10000/i; j++ )
{
/*若能由i*j 组成则其一定不是素数*/
visited[i * j] = 1;
}
}
}
/*广度优先搜索
**返回值即是从“起点”到“终点”所需的步骤
**/
int BFS(int start, int end)
{
/*起点与终点一致,长度为0*/
if(start == end)
{
return 0;
}
else
{
//题目中并没有说一定要从小变到大!!!!!!!!!!!
//if(start < end)
/*用于记录某个数被访问到时所需要的步骤数目*/
int time[10000] = {0};
/*白色为未访问,灰色为未完成,黑色为访问完成*/
/*waiting 用来储存“灰色”的元素*/
queue<int> waiting;
/*将起点首先设为灰色,即将搜索start 当改变一位即可得到一个新的素数*/
waiting.push(start);
/*只要waiting 队列不为空,即说明有可能搜索未结束,仍未找到“终点”*/
while(!waiting.empty())
{
/*searchNow 为当前考察的对象*/
int searchNow;
/*取“灰色”队列中的头元素作为考察对象*/
searchNow = waiting.front();
/*cout << searchNow << endl;*/
waiting.pop();/*该数已考察完毕了*/
/*------------------------------------------------------------------------------------------*/
/*得到“个位”*/
int a = searchNow%10;/*a表示考察对象的个位*/
int b = searchNow - a;/*b 表示考察对象减去个位后的数*/
/*改变“个位”*/
for(int i = 0; i < 10; i ++)
{
/*就是考察对象,不予理会*/
if(b + i == searchNow)
{
/*nothing*/
}
else
{
/*找到了“终点”, 函数可以返回步骤数了*/
if(b + i == end)
{
/*返回当前的步骤数*/
return time[searchNow] + 1;
}
/*既不是当前考察的数,也不是目标数*/
else
{
/*不是合数,也不是被访问过的数,将其入队列,即将其颜色改为“灰色”*/
if(!visited[b + i])
{
/*所需步骤为当前考察对象+1*/
time[b + i] = time[searchNow] + 1;
/*已访问过了*/
visited[b + i] = 1;
waiting.push(b +i);
}
}
}
}
/*------------------------------------------------------------------------------------------*/
/*获得“十位”*/
int c = searchNow%100 - a;/*c 表示当前考察数的十位*10*/
int d = searchNow - c;/*d 表示当前考察数除去十位后剩余的数*/
/*改变“十位”*/
for(int i = 0; i < 10; i++)
{
/*就是考察对象,不予理会*/
if(d + i*10 == searchNow)
{
/*nothing*/
}
else
{
/*找到了“终点”, 函数可以返回步骤数了*/
if(d + i*10 == end)
{
/*返回当前的步骤数*/
return time[searchNow] + 1;
}
/*既不是当前考察的数,也不是目标数*/
else
{
/*不是合数,也不是被访问过的数,将其入队列,即将其颜色改为“灰色”*/
if(!visited[d + i*10])
{
/*所需步骤为当前考察对象+1*/
time[d + i*10] = time[searchNow] + 1;
/*已访问过了*/
visited[d + i*10] = 1;
waiting.push(d +i*10);
}
}
}
}
/*------------------------------------------------------------------------------------------*/
/*获得“百位”*/
int e = searchNow%1000 - c - a;/*c 表示当前考察数的百位*100*/
int f = searchNow - e;/*d 表示当前考察数除去百位位后剩余的数*/
/*改变“百位”*/
for(int i = 0; i < 10; i++)
{
/*就是考察对象,不予理会*/
if(f + i*100 == searchNow)
{
/*nothing*/
}
else
{
/*找到了“终点”, 函数可以返回步骤数了*/
if(f + i*100 == end)
{
/*返回当前的步骤数*/
return time[searchNow] + 1;
}
/*既不是当前考察的数,也不是目标数*/
else
{
/*不是合数,也不是被访问过的数,将其入队列,即将其颜色改为“灰色”*/
if(!visited[f + i*100])
{
/*所需步骤为当前考察对象+1*/
time[f + i*100] = time[searchNow] + 1;
/*已访问过了*/
visited[f + i*100] = 1;
waiting.push(f +i*100);
}
}
}
}
/*------------------------------------------------------------------------------------------*/
/*获得“千位”*/
int g = searchNow - e - c - a;/*c 表示当前考察数的千位*10*/
int h = searchNow - g;/*d 表示当前考察数除去千位后剩余的数*/
/*改变“千位”*/
for(int i = 1; i < 10; i++)//千位不为0
{
/*就是考察对象,不予理会*/
if(h + i*1000 == searchNow)
{
/*nothing*/
}
else
{
/*找到了“终点”, 函数可以返回步骤数了*/
if(h + i*1000 == end)
{
/*返回当前的步骤数*/
return time[searchNow] + 1;
}
/*既不是当前考察的数,也不是目标数*/
else
{
/*不是合数,也不是被访问过的数,将其入队列,即将其颜色改为“灰色”*/
if(!visited[h + i*1000])
{
/*所需步骤为当前考察对象+1*/
time[h + i*1000] = time[searchNow] + 1;
/*已访问过了*/
visited[h + i*1000] = 1;
waiting.push(h +i*1000);
}
}
}
}
}
}
/*说明没办法找到一个路径从start 到end*/
return -1;
}
int main()
{
int testNum;
cin >> testNum;
/*testNum-- 是先检测testNum 是否为0,接着再去减1操作*/
while(testNum--)
{
/*设置全未访问*/
memset(visited,0,sizeof(visited));
/*先去除非素数的访问可能性*/
RejectNotPrime();
int start, end;
cin >> start >> end;
int time = BFS(start, end);
/*能找到一条路径*/
if(time >= 0)
{
cout << time << endl;
}
else
{
cout << "Impossible"<< endl;
}
}
return 0;
}