【USACO】兩道簡單的ACM試題

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章