【USACO 4.3.2】质数方阵

毒瘤题解

loj题目传送门

题目大意:有一个5*5的方阵,给出左上角的一个数以及每一行、每一列、每一斜行的数字和,求所有可能的填数方案并且按照方阵从上往下、从左往右组成的25位数从小到大排序。

(要保证每一行、每一列、每一斜行的五个数从左往右组成的五位数是一个五位质数,有前导0的不算)

tag:深搜


下面让我们来捋一捋:

1.这是一个填表游戏(貌似废话)

2.每一行的五个数,其实要去枚举的最多的只有三个数而已,剩余的一个可以用总和推出来

3.填一个数时,可能要判断多次,因为填下一个数可能会导致好几个行或者列被填满,需要判断;所以使用某些填表顺序的时候可能比较繁琐,要尽量避开这些诡异的格点。

(Tips:这些东西真的真的一定要避开,要不然填表的时候填着填着自己都会乱掉或是查错的时候难以查出,曾经修改两次填表顺序,繁琐的要命)

4.其实要解决的就是一个填表顺序的问题

5.填表的起点非常显然:左斜行,第一行或第一列。

6.填表过程中,若有一段已经被填上了4个数,则可以直接推出来剩下的一个

7.若推剩下这个数的时候,扣掉之后这个数>9或<0,则方案不可行


以下图片可能有点糊,S表示已知或者推出来的,X表示枚举出来的

所以下面就要来解决这个问题:

那我们就先从第一斜行填起吧!(所有名字里带着f1的函数都是)

然后就是第一列(带f2的)

然后第二行(带f3的)

接着搞定右斜行(带f4的)

然后搞定第三行(很繁琐是不是)(带f5的)

注意,此时可以把第五列推出来

然后可以把第四行推出来

下面搞定第二列(带f6的)

然后再搞定第三列(带f7的)

顺便把第一行搞定掉

最后搞定第五行、第四列;

注意!!!这个地方要判断两边,必须要第五行、第四列推出来的那个数一样以及行、列都满足其他条件(质数等)才能视为这个方案是OK的,top++;

于是就OK啦!

169行code:

#include<bits/stdc++.h>
using namespace std;
bool prime[100001];
void prim(){
    for(register int i=2;i<=sqrt(100000);i++){
        if(!prime[i]){
            for(register int j=i+i;j<=100000;j+=i)prime[j]=1;
        }
    }
}
struct data{
    int a[6][6];
    bool operator <(const data &d)const{
        for(register int i=1;i<=5;i++){
            for(register int j=1;j<=5;j++){
                if(a[i][j]<d.a[i][j])return 1;
                else if(a[i][j]>d.a[i][j])return 0;
            }
        }
        return 0;
    }
    bool operator =(const data &d){
        for(register int i=1;i<=5;i++){
            for(register int j=1;j<=5;j++){
                a[i][j]=d.a[i][j];
            }
        }
    }
}bas[10001];
int sum,s,top=0;
bool check(int a1,int a2,int a3,int a4,int a5){
	int num=a1*10000+a2*1000+a3*100+a4*10+a5;
    if(num<10000)return 0;
    return !prime[num];
}
void f7(){
    for(register int i=0;i<=9;i++){
		bas[top].a[1][3]=i;
		int num=sum-bas[top].a[1][1]-bas[top].a[1][2]-bas[top].a[1][3]-bas[top].a[1][5];
		if(num>9||num<0)continue;bas[top].a[1][4]=num;
		if(!check(bas[top].a[1][1],bas[top].a[1][2],bas[top].a[1][3],bas[top].a[1][4],bas[top].a[1][5]))continue;
		
		num=sum-bas[top].a[1][3]-bas[top].a[2][3]-bas[top].a[3][3]-bas[top].a[4][3];
		if(num>9||num<0)continue;bas[top].a[5][3]=num;
		if(!check(bas[top].a[1][3],bas[top].a[2][3],bas[top].a[3][3],bas[top].a[4][3],bas[top].a[5][3]))continue;
		
		num=sum-bas[top].a[5][1]-bas[top].a[5][2]-bas[top].a[5][3]-bas[top].a[5][5];
		int num2=sum-bas[top].a[1][4]-bas[top].a[2][4]-bas[top].a[3][4]-bas[top].a[4][4];
		if(num>9||num<0||num2!=num)continue;
		bas[top].a[5][4]=num;
		if(!check(bas[top].a[5][1],bas[top].a[5][2],bas[top].a[5][3],bas[top].a[5][4],bas[top].a[5][5])||!check(bas[top].a[1][4],bas[top].a[2][4],bas[top].a[3][4],bas[top].a[4][4],bas[top].a[5][4]))continue;
		top++;bas[top]=bas[top-1];
	}
}
void f6(){
    for(register int i=0;i<=9;i++){
		bas[top].a[1][2]=i;
		int num=sum-bas[top].a[1][2]-bas[top].a[2][2]-bas[top].a[3][2]-bas[top].a[4][2];
		if(num>9||num<0)continue;bas[top].a[5][2]=num;
		if(check(bas[top].a[1][2],bas[top].a[2][2],bas[top].a[3][2],bas[top].a[4][2],bas[top].a[5][2]))f7();
    }
}
void f5(){
    for(register int i=0;i<=9;i++){
		bas[top].a[3][5]=i;
		int num=bas[top].a[4][5]=sum-bas[top].a[1][5]-bas[top].a[2][5]-bas[top].a[3][5]-bas[top].a[5][5];
		if(num>9||num<0)continue;
		if(!check(bas[top].a[1][5],bas[top].a[2][5],bas[top].a[3][5],bas[top].a[4][5],bas[top].a[5][5]))continue;
		
		num=bas[top].a[4][3]=sum-bas[top].a[4][1]-bas[top].a[4][2]-bas[top].a[4][4]-bas[top].a[4][5];
		if(num>9||num<0)continue;
		if(!check(bas[top].a[4][1],bas[top].a[4][2],bas[top].a[4][3],bas[top].a[4][4],bas[top].a[4][5]))continue;
		
		num=sum-bas[top].a[3][1]-bas[top].a[3][3]-bas[top].a[3][4]-bas[top].a[3][5];
		if(num>9||num<0)continue;bas[top].a[3][2]=num;
		if(check(bas[top].a[3][1],bas[top].a[3][2],bas[top].a[3][3],bas[top].a[3][4],bas[top].a[3][5]))f6();
    }
}
void f51(){
	for(register int i=0;i<=9;i++){
		bas[top].a[3][4]=i;
		f5();
	}
}
void f4(){
    for(int i=0;i<=9;i++){
        bas[top].a[1][5]=i;
        int num=sum-bas[top].a[5][1]-bas[top].a[1][5]-bas[top].a[3][3]-bas[top].a[2][4];
        if(num>9||num<0)continue ;bas[top].a[4][2]=num;
        if(check(bas[top].a[5][1],num,bas[top].a[3][3],bas[top].a[2][4],bas[top].a[1][5]))f51();
    }
}
void f3(){
    for(register int i=0;i<=9;i++){
        bas[top].a[2][5]=i;
        int num=sum-bas[top].a[2][1]-bas[top].a[2][2]-bas[top].a[2][4]-bas[top].a[2][5];
        if(num>9||num<0)continue ;bas[top].a[2][3]=num;
        if(check(bas[top].a[2][1],bas[top].a[2][2],num,bas[top].a[2][4],bas[top].a[2][5]))f4();
    }
}
void f31(){
    for(int i=0;i<=9;i++){
        bas[top].a[2][4]=i;
        f3();
    }
}
void f2(){
    for(register int i=0;i<=9;i++){
        bas[top].a[5][1]=i;
        int num=sum-bas[top].a[1][1]-bas[top].a[3][1]-bas[top].a[4][1]-bas[top].a[5][1];
        if(num>9||num<0)continue ;
        bas[top].a[2][1]=num;
        if(check(bas[top].a[1][1],num,bas[top].a[3][1],bas[top].a[4][1],bas[top].a[5][1]))f31();
    }
}
void f22(){
    for(int i=0;i<=9;i++){
        bas[top].a[4][1]=i;
        f2();
    }
}
void f21(){
    for(int i=0;i<=9;i++){
        bas[top].a[3][1]=i;
        f22();
    }
}
void f1(){
    
    for(register int i=0;i<=9;i++){
        bas[top].a[5][5]=i;
        int num=sum-bas[top].a[1][1]-bas[top].a[3][3]-bas[top].a[4][4]-bas[top].a[5][5];
        if(num>9||num<0)continue ;
        bas[top].a[2][2]=num;
        if(check(bas[top].a[1][1],num,bas[top].a[3][3],bas[top].a[4][4],bas[top].a[5][5]))f21();
    }
}
void f12(){
    for(int i=0;i<=9;i++){
        bas[top].a[4][4]=i;
        f1();
    }
}
void f11(){
    for(int i=0;i<=9;i++){
        bas[top].a[3][3]=i;
        f12();
    }
}
void does(){
    bas[top].a[1][1]=s;
    f11();
    sort(bas,bas+top);
    for(int i=0;i<top;i++){
		for(int j=1;j<=5;j++){
			for(int k=1;k<=5;k++){
				cout<<bas[i].a[j][k];
			}
			cout<<endl;
		}
		cout<<endl;
    }
}
int main(){
    prim();
    cin>>sum>>s;
    does();
    return 0;
}

这题我调了6个半小时,可能是我太弱了

posted @ 2018-08-26 16:48  铁轮  阅读(1462)  评论(2编辑  收藏  举报