USACO SECTION 4.3 The Primes

The Primes
IOI'94

In the square below, each row, each column and the two diagonals can be read as a five digit prime number. The rows are read from left to right. The columns are read from top to bottom. Both diagonals are read from left to right.

+---+---+---+---+---+
| 1 | 1 | 3 | 5 | 1 |
+---+---+---+---+---+
| 3 | 3 | 2 | 0 | 3 |
+---+---+---+---+---+
| 3 | 0 | 3 | 2 | 3 |
+---+---+---+---+---+
| 1 | 4 | 0 | 3 | 3 |
+---+---+---+---+---+
| 3 | 3 | 3 | 1 | 1 |
+---+---+---+---+---+ 
  • The prime numbers' digits must sum to the same number.
  • The digit in the top left-hand corner of the square is pre-determined (1 in the example).
  • A prime number may be used more than once in the same square.
  • If there are several solutions, all must be presented (sorted in numerical order as if the 25 digits were all one long number).
  • A five digit prime number cannot begin with a zero (e.g., 00003 is NOT a five digit prime number).

PROGRAM NAME: prime3

INPUT FORMAT

A single line with two space-separated integers: the sum of the digits and the digit in the upper left hand corner of the square.

SAMPLE INPUT (file prime3.in)

11 1

OUTPUT FORMAT

Five lines of five characters each for each solution found, where each line in turn consists of a five digit prime number. Print a blank line between solutions. If there are no prime squares for the input data, output a single line containing "NONE".

SAMPLE OUTPUT (file prime3.out)

The above example has 3 solutions.

11351
14033
30323
53201
13313

11351
33203
30323
14033
33311

13313
13043
32303
50231
13331

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

FILE *fin,*fout;
int Prime[100000],PrimeC;
int Flag[10][10][10][10][10]; 
int Number[1000][5];
int Sum,First;
int Save[5][5];
int Ans[100][5][5];
int AnsC=0;

int comp(int i,int j)
{
	int x=0,y=0;
	while(x<5&&Ans[i][x][y]==Ans[j][x][y]){
		y++;
		if(y==5){
			y=0;
			x++;
		}
	}	
	if(x==5)
		return 0;
	return Ans[i][x][y]>Ans[j][x][y];
}

void Sort()
{
	int i,j,k,t;
	for(i=1;i<AnsC;i++){
		for(j=0;j<5;j++)
			for(k=0;k<5;k++)
				Ans[AnsC][j][k]=Ans[i][j][k];
		for(j=i;j>0&&comp(j-1,AnsC);j--)
			for(k=0;k<5;k++)
				for(t=0;t<5;t++)
					Ans[j][k][t]=Ans[j-1][k][t];
		for(k=0;k<5;k++)
			for(t=0;t<5;t++)
				Ans[j][k][t]=Ans[AnsC][k][t];
	}
}

int IsSum(int N)
{
	int sum=0;
	while(N!=0){
		sum+=N%10;
		N/=10;
	}	
	return sum==Sum;
}

void SaveAns()
{
	int i,j;
	for(i=0;i<5;i++)
		for(j=0;j<5;j++)
	Ans[AnsC][i][j]=Save[i][j];
	AnsC++;
}

void Print()
{
	int i,j,k;
	if(AnsC==0)
		fprintf(fout,"NONE\n");
	else{
		for(i=0;i<AnsC;i++){
			for(j=0;j<5;j++){
				for(k=0;k<5;k++)
					fprintf(fout,"%d",Ans[i][j][k]);
				fprintf(fout,"\n");
			}
			if(i!=AnsC-1)
				fprintf(fout,"\n");
		}
	}
}

void DFS(int Depth)
{
	int i,j;
	int x41,x43,x14,x34,x03,x30,x21,x23,x20,x24;
	switch(Depth){   //0,1对角线,2中间的竖,3上的横 
		case 0:for(i=0;i<PrimeC;i++){
				if(Number[i][0]==First){
					for(j=0;j<5;j++)
						Save[j][j]=Number[i][j];
					DFS(Depth+1);
				}
		}break;
		case 1:for(i=0;i<PrimeC;i++){
				if(Number[i][2]==Save[2][2]&&Number[i][4]!=0){
					for(j=0;j<5;j++)
						Save[4-j][j]=Number[i][j];
					DFS(Depth+1);
				}
		}break;
		case 2:for(i=0;i<PrimeC;i++){
				if(Number[i][2]==Save[2][2]){
					for(j=0;j<5;j++)
						Save[j][2]=Number[i][j];
					DFS(Depth+1);
				}
		}break;
		case 3:for(i=1;i<=9;i++){
				x03=Sum-Save[0][0]-i-Save[0][2]-Save[0][4];
				if(x03<=0||x03>9)
					continue;
				if(Flag[Save[0][0]][i][Save[0][2]][x03][Save[0][4]]){
					Save[0][1]=i;
					Save[0][3]=x03;
					DFS(Depth+1);
				}
		}break;
		case 4:for(i=0;i<=9;i++){
				x21=Sum-Save[0][1]-Save[1][1]-Save[3][1]-i;
				if(x21<0||x21>9)
					continue;
				if(Flag[Save[0][1]][Save[1][1]][x21][Save[3][1]][i]){
					Save[2][1]=x21;
					Save[4][1]=i;
					DFS(Depth+1);
				}
		}break;
		case 5: x43=Sum-Save[4][0]-Save[4][1]-Save[4][2]-Save[4][4];
				if(x43<0||x43>9)
					break;
				if(Flag[Save[4][0]][Save[4][1]][Save[4][2]][x43][Save[4][4]]){
					Save[4][3]=x43;
					DFS(Depth+1);
				}break;
		case 6:x23=Sum-Save[0][3]-Save[1][3]-Save[3][3]-Save[4][3];
		       if(x23<0||x23>9)
		       		break;
		       if(Flag[Save[0][3]][Save[1][3]][x23][Save[3][3]][Save[4][3]]){
					Save[2][3]=x23;
    			  DFS(Depth+1);
       			}break;
		case 7:for(i=1;i<=9;i++){
				x14=Sum-i-Save[1][1]-Save[1][2]-Save[1][3];
				if(x14<0||x14>9)
					continue;
				if(Flag[i][Save[1][1]][Save[1][2]][Save[1][3]][x14]){
					Save[1][0]=i;
					Save[1][4]=x14;
					DFS(Depth+1);
				}
		}break;
		case 8:for(i=1;i<=9;i++){
				x34=Sum-i-Save[3][1]-Save[3][2]-Save[3][3];
				if(x34<0||x34>9)
					continue;
				if(Flag[i][Save[3][1]][Save[3][2]][Save[3][3]][x34]){
					Save[3][0]=i;
					Save[3][4]=x34;
//					Print2(Depth);
					DFS(Depth+1);
				}
		}break;
		case 9:x20=Sum-Save[0][0]-Save[1][0]-Save[3][0]-Save[4][0];
		       x24=Sum-Save[0][4]-Save[1][4]-Save[3][4]-Save[4][4];
		       if(x20<=0||x24<0||x20>9||x24>9)
		       		break;
		       if(Flag[x20][Save[2][1]][Save[2][2]][Save[2][3]][x24]
			   	&&Flag[Save[0][0]][Save[1][0]][x20][Save[3][0]][Save[4][0]]
			   	&&Flag[Save[0][4]][Save[1][4]][x24][Save[3][4]][Save[4][4]]){
       			  Save[2][0]=x20;
       			  Save[2][4]=x24;
//       			  Print2(Depth);
    			  DFS(Depth+1);
       		}break;
		case 10:SaveAns();break;
	}
}

int main()
{
	int i,j,k;
	fin=fopen("prime3.in","r");
	fout=fopen("prime3.out","w");
	memset(Prime,0,sizeof(Prime));
	memset(Flag,0,sizeof(Flag));
	fscanf(fin,"%d %d",&Sum,&First);
	//筛选法求五位的素数
	for(i=2;i<=50000;i++)
		for(j=2;i*j<100000;j++)
			Prime[i*j]=1;
	for(i=10000,j=0;i<100000;i++)
		if(Prime[i]==0&&IsSum(i))
			Prime[j++]=i;
	PrimeC=j;
	//保存素数 
	for(i=0;i<PrimeC;i++){    
		for(j=0,k=1;j<5;j++){
			Number[i][4-j]=(Prime[i]/k)%10;
			k*=10;
		}
	}
	//记录素数
	for(i=0;i<PrimeC;i++)
		Flag[Number[i][0]][Number[i][1]][Number[i][2]][Number[i][3]][Number[i][4]]=1;
	DFS(0);
	Sort();
	Print();
	return 0;	 
}


先用筛选法求出所有五位的素数,然后开一个五位数组记录是否该数是为素数

最后DFS,搜索过程中要按照顺序可以极大的节约时间,先对角线,然后中间的竖线,接着最上面一行和最下面一行。然后通过减法算出第二列和第四列,最后搜索第二行第四行,减法得到中间一行结束。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值