题目描述:
http://acm.hdu.edu.cn/showproblem.php?pid=1973
中文大意:
有钱人更换门牌号码。
门牌号码有 4 位,且必须为质数。
更换一个数字的成本是 1 磅,每次只能更换一个数字。
要求:计算更换成目标门牌号码的最小花费。
思路:
队列节点记录的是当前门牌号和当前的花费。
弹出队列首节点,确定了当前门牌信息后,下一步有 9 + 3 x 10 种选择,注意要考虑“首位不能为 0 ”这种情况。
其中,“素数判断”的方法必须优化,最好事先打表,不然会超时。
代码:
#include<bits/stdc++.h>
using namespace std;
struct node{
string str;
int cost;
};
bool visited[10000];
bool prime[10000] = {false};
string str1,str2;
//判断一个数是否是素数
bool is_prime(string str){
int val = 0;
for(int i=0;i<4;i++){
val *= 10;
val += str[i] - '0';
}
if(prime[val] == true){
return true;
}
else{
return false;
}
}
//判断一个数是否已经被访问
bool is_visited(string str){
int val = 0;
for(int i=0;i<4;i++){
val *= 10;
val += str[i] - '0';
}
if(visited[val] == false){
visited[val] = true;
return false;
}
else{
return true;
}
}
int bfs(){
node start,next;
start.str = str1;
start.cost = 0;
is_visited(start.str);
queue<node> q;
q.push(start);
while(!q.empty()){
start = q.front();
q.pop();
if(start.str == str2){
return start.cost;
}
for(int i=0;i<4;i++){
for(int j=0;j<=9;j++){
//首位不能为0
if(i == 0 && j == 0){
continue;
}
next.str = start.str;
next.str[i] = j + '0';
next.cost = start.cost + 1;
if(is_prime(next.str) && !is_visited(next.str)){
q.push(next);
}
}
}
}
return -1;
}
int main(){
//计算1000~9999范围内的素数
for(int val=1000;val<=9999;val++){
bool flag = true;
int k = int(sqrt(val));
for(int i=2;i<=k;i++){
if(val % i == 0){
flag = false;
break;
}
}
if(flag){
prime[val] = true;
}
}
int n;
scanf("%d", &n);
while(n--){
cin>>str1>>str2;
memset(visited, false, sizeof(visited));
int cost = bfs();
if(cost < 0){
printf("Impossible
");
}
else{
printf("%d
", cost);
}
}
}