题目:http://poj.org/problem?id=3126
题意:给出两个四位数(无前导零)a和b,都是素数,规定以下变换规则:
每次只能改变数的一位,变换完的数仍要求是质数,且仍为四位数。
求最少经过几次变换,能使a变换成b,如果不能从a变成b,则输出“Impossible”。
思路:考虑将素数看作点,将能够经过变换得到的两点看作两点之间有边,建立无向图,利用邻接表存储。最后用bfs求出最短路程即可。
说起来好像挺简单然而细节特别多小错误不断,三个小时的训练赛做了一个半小时差不多快疯了。。。
这题也可以不需要显式的建图,代码会简单不少,以下是显式建图的代码。
代码:c++
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
const int maxn = 10000+10;
int a, b;
bool primenum[maxn];
bool vis[maxn];
map<int, set<int> > pic;
int step[maxn];
int ans;
//判断素数
bool isprime(int u)
{
int sqrtu = sqrt(u);
for(int i=2; i<=sqrtu; i++)
{
if(u%i==0)
{
return false;
}
}
return true;
}
//素数打表
void preprime()
{
for(int i=1000; i<=9999; i++)
{
if(isprime(i))
{
primenum[i] = true;
}
}
}
//建图
void drawpic()
{
char s[10] = {0};
for(int i=1000; i<=9999; i++)
{
if(primenum[i])
{
sprintf(s, "%d", i);
for(int j=0; j<4; j++)
{
char ss[10] = {0};
strcpy(ss, s);
ss[j] = '0';
int minn;
sscanf(ss, "%d", &minn);
for(int k=0; k<10; k++)
{
if(j==0&&k==0)
continue;
int t = minn+k*(int)round(pow(10, 3-j));
if(primenum[t]&&i!=t)
{
pic[i].insert(t);
pic[t].insert(i);
}
}
}
}
}
}
//bfs求最短路
bool bfs()
{
ans = 0;
if(a==b)
{
return true;
}
memset(step, 0, sizeof(step));
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(a);
vis[a] = true;
while(!q.empty())
{
int t = q.front();
q.pop();
set<int>::iterator it = pic[t].begin();
for(; it!=pic[t].end(); it++)
{
if(!vis[*it])
{
q.push(*it);
vis[*it] = true;
step[*it] = step[t] + 1;
if(*it==b)
{
ans = step[*it];
return true;
}
}
}
}
return false;
}
int main()
{
preprime();
drawpic();
int T;
cin >> T;
while(T--)
{
scanf("%d%d", &a, &b);
if(bfs())
printf("%d\n", ans);
else
printf("Impossible\n");
}
return 0;
}