题目来源:http://poj.org/problem?id=3126
----------------------------------------
总时间限制: 1000ms 内存限制: 65536kB
描述
The ministers ofthe cabinet were quite upset by the message from the Chief of Security statingthat they would all have to change the four-digit room numbers on theiroffices.
— It is a matter of security to change such things every now and then, to keepthe enemy in the dark.
— But look, I have chosen my number 1033 for good reasons. I am the Primeminister, you know!
— I know, so therefore your new number 8179 is also a prime. You will just haveto paste four new digits over the four old ones on your office door.
— No, it’s not that simple. Suppose that I change the first digit to an 8, thenthe number will read 8033 which is not a prime!
— I see, being the prime minister you cannot stand having a non-prime number onyour door even for a few seconds.
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path ofprime numbers where only one digit is changed from one prime to the nextprime.
Now, the minister of finance, who had been eavesdropping, intervened.
— No unnecessary expenditure, please! I happen to know that the price of adigit is one pound.
— Hmm, in that case I need a computer program to minimize the cost. You don'tknow some very cheap software gurus, do you?
— In fact, I do. You see, there is this programming contest going on... Helpthe prime minister to find the cheapest prime path between any two givenfour-digit primes! The first digit must be nonzero, of course. Here is asolution in the case above.
1033
1733
3733
3739
3779
8779
8179
The cost of thissolution is 6 pounds. Note that the digit 1 which got pasted over in step 2 cannot be reused in the last step – a new 1 must be purchased.
输入
One line with a positive number: the number of test cases(at most 100). Then for each test case, one line with two numbers separated bya blank. Both numbers are four-digit primes (without leading zeros).
输出
One line for each case, either with a number stating theminimal cost or containing the word Impossible.
样例输入
3
1033 8179
1373 8017
1033 1033
样例输出
6
7
0
-----------------------------------------------------
解题思路
题目的中心思想是:
欲从四位素数A变到四位素数B,每次改变一位,保证每次改变后得到的仍是四位素数,求最少的改动次数
将每个四位素数视为节点,如果素数C改变一位能够得到素数D,则在C和D之间连一条边,如此构成一个图G。原问题转化为求图G两点之间的最短路长度。
由于图G的边没有权值,故采用广度优先搜索。
广度优先搜索分为2步:搜索和回溯,分别对应2个数据结构:
(1) 队列q:用于搜索过程,新的节点入队,这些节点的前驱节点出队
(2) 数组mark: 用于搜索过程和回溯过程,初始化为0表示没有访问过任何节点,下次如果访问到一个节点的mark不是0,说明访问过了就不要再访问了;访问过一个节点以后,令mark[thisNode]= fatherNode. 回溯的时候顺着mark往前访问到起始节点就能得到最短路。
特别注意:C/C++里"^"是异或不是乘方,没有适用于(int,int)的乘方函数,需要自己编写函数实现!
-----------------------------------------------------
代码
#include
#include
#include
#include
using namespace std;
int power(int a, int n) // a^n, "^"在C++里是异或
{
int i = 0, result = 1;
if (n==0)
{
return 1;
}
for (i=0; i> num;
vector cost; // 输出结果序列
for (i=0; i> src; // 原来的门牌号
cin >> dst; // 现在的门牌号
/*广度优先搜索
将1000~9999间的每个素数看做一个节点
将改动一位就能从素数A变成素数B的关系看做连接A和B的一条边
问题转化为在图中搜索两点之间的最短路
*/
int mark[10000] = {0}; // 每个数的前驱节点
queue BFS; // BFS队列
BFS.push(src); // 将src压入队列
mark[src] = src; // 将src的前驱节点设为自己
while (src != dst)
{
if (!BFS.empty())
{
item = BFS.front(); // 取出BFS队首元素
BFS.pop(); // 出队列
for (j=0; j<4; j++) // 4位数字
{
for (k=0; k<10; k++) // 每位改一下
{
dig = (item % power(10,j+1))/power(10,j); // item的第j位
if (k!=dig) // 如果不是原来的数字
{
nItem = item + (k-dig) * power(10,j);// 换上新的第j位
if (nItem<10000 && nItem>1000) // 防止数组越界
{
if (mark[nItem] == 0) // 如果该节点没有被访问过
{
mark[nItem] = item; // 用mark数组记录nItem的前驱节点
if (nItem == dst) // 如果找到dst
{
goto outwhile; // 用goto跳出深层循环
}
else if (isPrime(nItem))// 如果nItem是素数
{
BFS.push(nItem); // 则压入队列
}
}
}
}
}
}
}
}
outwhile: // 回溯法求解搜索树深度
cnt = 0; // 深度计数器
item = dst; // 从dst开始反向回溯
while(item != src) // 尚未回溯到src
{
item = mark[item]; // 通过mark数组回溯
cnt ++;
}
cost.push_back(cnt);
}
vector::iterator it;
for (it=cost.begin(); it!= cost.end(); it++)
{
cout << *it << endl;
}
return 0;
}