SuperPrime Rib
題目(簡述):
找出某一長度的超級素數。所謂的超級素數,例如7331:其中7331是素數,733是素數,73是素數,7是素數。即每次從該數中去掉最後一位數後,依然是素數的素數,被稱爲超級素數(superprime)。
分析:
判斷一個數是不是超級素數,我們需要判斷n次,n爲這個數的位數。爲了使程序更快,我們應該首先判斷最高位是不是素數,然後判斷最高兩位是不是素數……直到判斷到這個數本身是不是素數。其次,我們並不需要遍歷所有的n位數,因爲很多數直接就可以排除掉:除了最高位,其他任何位上有偶數的排除,1開頭的數排除,至於爲什麼,原因很簡單,大家可以自己思考。這樣之後,我們其實可以生成這樣的數,而不是遍歷。生成這樣的數的時候,注意要按照從小到大的順序。下面是代碼實現。
代碼:
Executing...
Test 1: TEST OK [0.000 secs, 3048 KB]
Test 2: TEST OK [0.000 secs, 3048 KB]
Test 3: TEST OK [0.000 secs, 3048 KB]
Test 4: TEST OK [0.000 secs, 3048 KB]
Test 5: TEST OK [0.000 secs, 3048 KB]
/*
ID:haxc_xc1
PROG:sprime
LANG:C++
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int n;
bool prime(int num)
{
bool ret=true;
int i;
for(i=2;i<=sqrt(num);i++)
{
if(num%i==0)
{
ret=false;
break;
}
}
return ret;
}
void deal(int num,int k)
{
if(k==n)
{
if(prime(num)) //搜索到k位的時候,如果滿足條件,則直接輸出
{
printf("%d\n",num);
}
}
else
{
if(prime(num*10+1)) //如果這個數滿足,則向下搜索
{
deal(num*10+1,k+1);
}
if(prime(num*10+3))
{
deal(num*10+3,k+1);
}
if(prime(num*10+5))
{
deal(num*10+5,k+1);
}
if(prime(num*10+7))
{
deal(num*10+7,k+1);
}
if(prime(num*10+9))
{
deal(num*10+9,k+1);
}
}
}
int main(void)
{
freopen("sprime.in","r",stdin);
freopen("sprime.out","w",stdout);
scanf("%d",&n);
deal(2,1);
deal(3,1);
deal(5,1);
deal(7,1);
return 0;
}
Checker Challenge
題目:
這個問題是8皇后問題的擴展,讀入一個數n,代表n*n的格子,求出所有的方案數,並且輸出前3種方案的具體內容。
分析:
筆者寫的第一個程序,是基於深度優先搜索,沒有任何優化,n=13時運算超時。後來看了若干別人的分析之後,瞭解到matrix67大牛的一個基於位運算的算法,深表佩服:具體鏈接:http://www.matrix67.com/blog/archives/266。具體內容裏面已經講述地很清楚了,也就不再贅述。代碼部分附上本人所寫的基於此思想的C語言的實現。另外,這個題還可以採用對稱的思想對其進行優化。
代碼(只輸出了所有方案的數量,沒有輸出前3個具體的方案):
#include <stdio.h>
#include <stdlib.h>
int n;
unsigned upperlim;
int result;
void deal(unsigned row,unsigned ld,unsigned rd,int deep)
//row代表列有衝突的,ld代表左斜對角線有衝突的,rd代表右斜對角線有衝突的。deep代表層數或者深度,都可以。
{
if(row!=upperlim)
//還沒有放完
{
unsigned pos=upperlim & ~(row|ld|rd),p;
while(pos)
{
p=pos&(-pos); //p爲右起第一個安全位置
pos=pos^p; //設置禁止位
deal(row|p,(ld|p)>>1,(rd|p)<<1,deep+1);
}
}
else
{
result++;
}
}
int main(void)
{
freopen("checker.in","r",stdin);
freopen("checker.out","w",stdout);
scanf("%d",&n);
upperlim=(1<<n)-1; //upperlim的每一位都表示了該位置是否能夠放下
deal(0,0,0,1);
printf("%d\n",result);
return 0;
}