USACO 4.3 The Primes

题意:

给两个值,sum和head,按字典序输出所有满足的条件的5*5方格:

(1)最左上角的数位head

(2)每行、每列、两条对角线的和都等于sum

(3)每行、每列、两条对角线组成的五位数都是素数(从左到右,从上到下)

思路:

暴力搜索的样子。。。我解出来很慢,花了蛮多时间的

思路是:首先把期间的素数预处理出来,

先枚举第一行,再递归枚举最后一列,倒数第二列,倒数第三列,最后只剩下八个空,只需要枚举一个空,其余七个空都能填充

完成之后去看别人的做法,发现别人的做法更加无脑。。。

之所以先枚举第一行,是因为第一个数是确定的,再枚举最后一行,是因为最后一行有很多都可以被排除(因为最后一行的数都是每一行的末尾,不能有2,4,6,8,5出现)

我觉得比较好的枚举顺序是:第一行 -> 第一列 -> 最后一列-> 任意一条对角线 -> 剩余八个空格中的一个

总之,先枚举的一定是状态少的达到剪枝的目的,当然,用循环取消递归。。。

/*
TASK: prime3
ID: jasison2
LANG: C++
*/
/**
 * @date    2014-04-18 18:42:54
 * @author  jasison
 * @email   jasison27@gmail.com
 * @website http://www.jiangshan27.com
 */

#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 100000;
bool notp[N];
vector<int>v[46][10];
int calc(int x){
	int ret=0;
	while(x){
		ret+=x%10;
		x/=10;
	}
	return ret;
}
void process(){
	memset(notp,0,sizeof(notp));
	int up=int(sqrt(N));
	for(int i=2;i<=up;++i){
		if(!notp[i]){
			for(int j=i*i;j<N;j+=i){
				notp[j]=1;
			}
		}
	}
	for(int i=10000;i<N;++i){
		if(!notp[i]){
			v[calc(i)][i/10000].push_back(i);
		}
	}
}
int sum,head,an;
int ma[5][5];
struct Ans{
	int matrix[5][5];
	bool operator<(const Ans &obj)const {
		for(int i=0;i<5;++i){
			for(int j=0;j<5;++j){
				if(matrix[i][j]!=obj.matrix[i][j]){
					return matrix[i][j]<obj.matrix[i][j];
				}
			}
		}
		return 0;
	}
	void output(){
		for(int i=0;i<5;++i){
			for(int j=0;j<5;++j){
				printf("%d",matrix[i][j]);
			}
			puts("");
		}
	}
}ans[200];
bool judge(int r,int c,int x){
	if(x<0||x>9){
		return 0;
	}
	if(c==4 || r==4){
		if(!(x&1) || x==5){
			return 0;
		}
	}
	if(r==0 || c==0){
		if(x==0){
			return 0;
		}
	}
	return 1;
}
bool fill(bool row,int index,int x){
	bool flag=1;
	if(row){
		for(int j=4;j>=0;--j){
			ma[index][j]=x%10;
			if(!judge(index,j,x%10)){
				flag=0;
			}
			x/=10;
		}
	}else{
		for(int i=4;i>=0;--i){
			ma[i][index]=x%10;
			if(!judge(i,index,x%10)){
				flag=0;
			}
			x/=10;
		}
	}
	return flag;
}
void pushAns(){
	for(int i=0;i<5;++i){
		for(int j=0;j<5;++j){
			ans[an].matrix[i][j]=ma[i][j];
		}
	}
	an++;
}
bool judge(bool row,int index){
	int tot;
	if(row){
		tot=0;
		for(int j=0;j<5;++j){
			tot=10*tot+ma[index][j];
		}
		if(!binary_search(v[sum][ma[index][0]].begin(),v[sum][ma[index][0]].end(),tot)) {
			return 0;
		}
	}else{
		tot=0;
		for(int i=0;i<5;++i){
			tot=10*tot+ma[i][index];
		}
		if(!binary_search(v[sum][ma[0][index]].begin(),v[sum][ma[0][index]].end(),tot)) {
			return 0;
		}
	}
	return 1;
}
bool specialjudge(){
	int tot=0;
	for(int i=0;i<5;++i){
		tot=10*tot+ma[i][i];
	}
	if(!binary_search(v[sum][ma[0][0]].begin(),v[sum][ma[0][0]].end(),tot)) {
		return 0;
	}
	tot=0;
	for(int i=0;i<5;++i){
		tot=10*tot+ma[4-i][i];
	}
	if(!binary_search(v[sum][ma[4][0]].begin(),v[sum][ma[4][0]].end(),tot)) {
		return 0;
	}
	return 1;
}
bool alljudge(){
	return judge(false,0) &&
		judge(false,1) &&
		judge(true,1) &&
		judge(true,2) &&
		judge(true,3) &&
		judge(true,4) &&
		specialjudge();
}
void output(){
	for(int i=0;i<5;++i){
		for(int j=0;j<5;++j){
			printf("%d",ma[i][j]);
		}
		puts("");
	}
	puts("");
}
void fillall(){
	ma[1][1]=sum-ma[0][0]-ma[2][2]-ma[3][3]-ma[4][4];
	if(!judge(1,1,ma[1][1])) return;
	ma[1][0]=sum-ma[1][1]-ma[1][2]-ma[1][3]-ma[1][4];
	if(!judge(1,0,ma[1][0])) return;
	for(ma[4][0]=1;ma[4][0]<10;ma[4][0]+=2){
		if(ma[4][0]==5) continue;
		ma[3][1]=sum-ma[4][0]-ma[2][2]-ma[1][3]-ma[0][4];
		if(!judge(3,1,ma[3][1])) continue;
		ma[4][1]=sum-ma[4][0]-ma[4][2]-ma[4][3]-ma[4][4];
		if(!judge(4,1,ma[4][1])) continue;
		ma[3][0]=sum-ma[3][1]-ma[3][2]-ma[3][3]-ma[3][4];
		if(!judge(3,0,ma[3][0])) continue;
		ma[2][1]=sum-ma[0][1]-ma[1][1]-ma[3][1]-ma[4][1];
		if(!judge(2,1,ma[2][1])) continue;
		ma[2][0]=sum-ma[0][0]-ma[1][0]-ma[3][0]-ma[4][0];
		if(!judge(2,0,ma[2][0])) continue;
		if(alljudge()){
			pushAns();
		}
	}
}
void dsolve(int c){
	if(c==1){
		fillall();
		return;
	}
	for(int i=v[sum][ma[0][c]].size()-1;i>=0;--i){
		if (fill(false,c,v[sum][ma[0][c]][i])){
			dsolve(c-1);
		}
	}
}
void solve(){
	an=0;
	for(int i=v[sum][head].size()-1;i>=0;--i){
		if (fill(true,0,v[sum][head][i])){
			dsolve(4);
		}
	}
	if(an==0){
		puts("NONE");
	}else{
		sort(ans,ans+an);
		for(int i=0;i<an;++i){
			if(i!=0){
				puts("");
			}
			ans[i].output();
		}
	}
}
int main() {
	freopen("prime3.in","r",stdin);
	freopen("prime3.out","w",stdout);
	process();
	while(scanf("%d%d",&sum,&head)!=EOF){
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值