HDU-1431(素数回文)
素数回文
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 16595 Accepted Submission(s): 3702
5 500
5 7 11 101 131 151 181 191 313 353 373 383
刚开始就感觉这道题有点麻烦。起初的思路是先打素数表,再从素数中查找符合条件的回文数。感觉会超时,5 <= a < b <= 100,000,000,由于范围比较大,于是就单单测试了一下打表,结果在编译器上就运行了2~3秒,按照这样的思路写最终肯定会超时。于是想了很久发现可以利用回文数的对称性为切入点,可能还有解决的希望。
(先找出回文数,再判断是不是素数)
例:样例:5 500
首先 ;
一位数字: 2、3、5、7
两位: 11
三位: 101 131 151
如果是奇数位:通性: ........x y z x y......(对称)
以:x y z x y为例,只需变化3个就可以了,x、y、z分别取值0~9(dfs)就可以打印出5位数的全部回文数,然后再对回文数判断是不是素数
如果是偶数位:通性: .......x y z z y x......(对称)
以:x y z z x y为例,只需变化3个就可以了,x、y、z分别取值0~9(dfs)就可以打印出6位数的全部回文数,然后再对回文数判断是不是素数
就样例而言:
先打印 1 位的回文数,再打印 2 位的回文数,再打印 3 位 的回文数。。。。。。。。
该题思路:( for循环 + ( dfs + 素数判断 ) ),(for循环控制位数,dfs控制打印回文数,prim进行素数判断)
My solution:
/*2016.3.31*/
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
int map[100000030],cnt1,cnt2,a1[20],k1,k2,vis;
int prim(int t)//判断素数
{
int i,j,k;
for(i=2;i*i<=t;i++)
{
if(t%i==0)
return 0;
}
if(t==1)//1不是素数,这点容易遗忘
return 0;
return 1;
}
void dfs(int t1,int t2)
{
int i,j,k,sum;
if(t2<t1)//此次查询完成
{
if(a1[vis]%2)//优化,最后一位数字如果是偶数的话,这个数肯定是偶数,不是素数 (同时巧妙化解了首位数字不能为0的情况)
{
sum=0;
for(i=1;i<=vis;i++)//把这个数在数组中的数值位转换为整数sum
{
sum=a1[i]+sum*10;
}
if(prim(sum)&&(sum>=k1&&sum<=k2))//sum不仅要是素数,而且还得大于等于a小于等于b
printf("%d\n",sum);
return ;
}
return ;
}
for(i=0;i<=9;i++)//控制每个数值位上的数字
{
a1[t1]=a1[t2]=i;//由于对称,所以相等
dfs(t1+1,t2-1);//左右各往里缩进一位 ,这一步特别重要
}
}
int main()
{
int i,j,k,n,m,a,b;
while(scanf("%d%d",&k1,&k2)==2)
{
a=k1;b=k2;
cnt1=cnt2=0;
while(b)
{
b=b/10;
cnt2++;//cnt2记录b的位数
}
while(a)
{
a=a/10;
cnt1++;//cnt1记录a的位数
}
for(i=cnt1;i<=cnt2;i++)//控制位数
{
vis=i;//vis记录当前查询的最大位数
dfs(1,i);//在当前位数中,查找满足题目要求的回文素数
}
printf("\n");
}
return 0;
}