题目的大意就是,给出两个四位素数n,m,每次只改变n一个数位上面的数字使他成为另外一个素数,要求从n变到m的最短路径。
由于是最短路径问题,所以很明显采取的做法是通过bfs。
-
哎,写这个题目的时候没有管数据范围,以为很大就又是快筛,又是二分,写完发现根本没必要,反正也懒得改了就这样了。关键是这个题目不是从2开始的,快速筛不好写,为了警戒自己就还是发上来了。
//#include<bits/stdc++.h> // poj的日常不能用的头文件
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e5+7;
typedef long long ll;
bool isprime[N],que[N]; // que数组用来存储已搜索的数字
int prime[N],sum[4]; // prime数组来存储素数,而sum数组用来存储数位
int cnt=0,n,m; // cnt用来存储素数个数方便后面的二分查找(很显然这个完全没有必要)
struct node{
int num,step;
}; // 这个结构体num是为了存储该次变化,而step是用来存储以变化次数
/*void fast_find_prime() // 写low了的快筛
{
memset(isprime,true,sizeof isprime);
for(int i = 2;i < 1e4;++i){
if(isprime[i]) prime[++cnt] = i;
for(int j = 1;j < cnt && prime[j] * i < 1e4;++j)
isprime[prime[j] * i] = false;
}
}*/
void find_prime() // 筛选素数
{
for(int i = 1009;i <= 1e4;++i){
bool flag = true;
for(int j = 2;j <= sqrt(i);++j){
if(i % j == 0){
flag = false;
break;
}
}
if(flag) prime[++cnt] = i;
}
}
bool judge_fast_find(int p) // 通过二分查找来判断该种变化是否为素数
{
int l = 1,r = cnt,mid;
while(r - l > 1){
mid = (l + r) / 2;
if(p > prime[mid]) l = mid;
else r = mid;
}
if(p == prime[l] || p == prime[r]) return true;
return false;
}
bool judge(int i,int j,node &res,int v) // 判断该次变化是否符合题意
{
sum[0] = v / 1000;
sum[1] = v % 1000 / 100;
sum[2] = v % 100 / 10;
sum[3] = v % 10;
sum[i] = j; // 进行数位变化
int t = 1000 * sum[0] + 100 * sum[1] + 10 * sum[2] + sum[3]; // 计算出新数
if(!que[t] && judge_fast_find(t)){
res.num = t; // 通过引用改变数字
que[t] = true; // 若可行就打上标记
return true;
}
return false;
}
int bfs()
{
queue<node> q; // 进行判断的队列
node res; // 用于搜索判断的结构体
res.num = n,res.step = 0;
que[n] = true;
q.push(res);
while(!q.empty()){
res = q.front();
int v = res.num;
if(res.num == m) return res.step;
res.step++;
for(int i = 0;i < 4;++i){
for(int j = 0;j < 10;++j){
if(judge(i,j,res,v)){
if(res.num == m) return res.step;
q.push(res);
}
}
}
q.pop();
}
return -1;
}
int main()
{
int t;
cin >> t;
// fast_find_prime();
find_prime();
while(t--){
cin >> n >> m;
memset(que,false,sizeof que);
int ans = bfs();
// for(int i = 1;i <= cnt;++i) cout << prime[i] <<endl;
if(ans == -1) cout << "Impossible" << endl;
else cout << ans <<endl;
}
return 0;
}
写到这里,突然发现快筛完全ok。。。
//#include<bits/stdc++.h>
#include<queue>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e5+7;
typedef long long ll;
bool isprime[N],que[N];
int prime[N],sum[4];
int cnt=0,cnf = 0,n,m; // cnf存储第一个四位素数的位置
struct node{
int num,step;
};
void fast_find_prime()
{
memset(isprime,true,sizeof isprime);
for(int i = 2;i < 1e4;++i){
if(isprime[i]) prime[++cnt] = i;
if(prime[cnt] == 1009) cnf = cnt;
for(int j = 1;j < cnt && prime[j] * i < 1e4;++j)
isprime[prime[j] * i] = false;
}
}
bool judge_fast_find(int p)
{
int l = cnf,r = cnt,mid;
while(r - l > 1){
mid = (l + r) / 2;
if(p > prime[mid]) l = mid;
else r = mid;
}
if(p == prime[l] || p == prime[r]) return true;
return false;
}
bool judge(int i,int j,node &res,int v)
{
sum[0] = v / 1000;
sum[1] = v % 1000 / 100;
sum[2] = v % 100 / 10;
sum[3] = v % 10;
sum[i] = j;
int t = 1000 * sum[0] + 100 * sum[1] + 10 * sum[2] + sum[3];
if(!que[t] && judge_fast_find(t)){
res.num = t;
que[t] = true;
return true;
}
return false;
}
int bfs()
{
queue<node> q;
node res;
res.num = n,res.step = 0;
que[n] = true;
q.push(res);
while(!q.empty()){
res = q.front();
int v = res.num;
if(res.num == m) return res.step;
res.step++;
for(int i = 0;i < 4;++i){
for(int j = 0;j < 10;++j){
if(judge(i,j,res,v)){
if(res.num == m) return res.step;
q.push(res);
}
}
}
q.pop();
}
return -1;
}
int main()
{
int t;
cin >> t;
fast_find_prime();
while(t--){
cin >> n >> m;
memset(que,false,sizeof que);
int ans = bfs();
// for(int i = 1;i <= cnt;++i) cout << prime[i] <<endl;
if(ans == -1) cout << "Impossible" << endl;
else cout << ans <<endl;
}
return 0;
}
因为其他的都差不多,就不一一注释了。。。很迷,居然就快了1ms,没意思