【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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值