USACO6.4.1 The Primes(prime3)

本文介绍了一种通过优化算法解决特定数学问题的方法:构建一个5x5的矩阵,该矩阵的每一行、每一列及两条对角线上的数字之和都等于给定的目标值,同时这些数字还需满足既是素数也是其各位数字之和等于另一给定值的条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

搜索题,但是好麻烦,各种的优化才涉险过了

1.先打表是必须的:这个表是既是素数且每位相加又是所要求的数的5位数,并且为避免重复计算,可以把每个符合要求的数给拆分好记录
2.确定行,列,对角线,直接确定一整行或者一整列或一整对角线,也就是直接是找个五位数全部添上去(因为已经有打好的有序的表),减少了无意义的搜索试探
3.搜索顺序:最上一条—最左一条—两个对角线—第二行—枚举2,3,4,5列(为什么是这个顺序,我不知道,可能是数据的影响吧,特别是在枚举列之前先确定第二行很有用)
先确定最左和最上是因为输入时给的就是左上角,正好从这个点展开,并且题目要求必须是"真正的五位数",也就是说最上和最左不能出现0
提前确定前两行的好处是在搜索2,3,4,5,列时前两行的值已经确定,就可以根据这两行的确定值剪掉枚举出得前两行不等的情况,但若提前确定了前三行,效果差了,不知道为什么

4.在枚举2,3,4,5列时,用数组记录3,4,5行的和情况,若在中途这其中有和大于所要求的了,直接剪掉


/*
ID:xsy97051
LANG:C++
TASK:prime3
*/
#include <iostream>           
#include <cstdio>        
#include <cstring>        
#include <cmath>          
#include <algorithm>           
using namespace std;   
struct node  { int s[6][6]; }ans[1005];  

bool IsPrime(int k)  
{  
    for(int i=2;i*i<=k;i++)  
        if(k%i==0) return 0;  
    return 1;      
}

int num,a[1001],sum,m,s[6][6],times,h[11],b[8],g[1001][6];  
bool IsOk[100005];  

void getanswer(int p)  
{  
    if(p>5)  
    {    
        for(int i=3;i<=5;i++)  
        {  
            int tep=0;  
            for(int j=1;j<=5;j++)    
                tep=tep*10+s[i][j];   
            if(b[i]!=sum || !IsOk[tep]) return;        
        }  
        times++;   
        for(int i=1;i<=5;i++)  
            for(int j=1;j<=5;j++)
                ans[times].s[i][j]=s[i][j];    
          return;    
    }     
    
    for(int i=h[s[1][p]];i<h[s[1][p]+1];i++)   
        if(g[i][p]==s[p][p] && g[i][6-p]==s[6-p][p] && g[i][2]==s[2][p])  
        {  
            s[2][p]=g[i][2];  s[3][p]=g[i][3];  
            s[4][p]=g[i][4];  s[5][p]=g[i][5];      
            b[3]+=s[3][p];  
            b[4]+=s[4][p]; b[5]+=s[5][p];   
            if(b[3]<=sum && b[4]<=sum && b[5]<=sum)   
                getanswer(p+1);       
            b[3]-=s[3][p];  
            b[4]-=s[4][p]; b[5]-=s[5][p];                     
        }
        else 
            if(g[i][2]>s[2][p]) break;  
}  

bool EquSum(int i)  
{  
      int m=0;  
      while (i)  
      {  
            m+=i%10;  
            i/=10;        
      }      
      if (m==sum) return 1;  
      return 0;  
}  

bool cmp(node a,node b)  
{  
    for(int i=1;i<=5;i++)  
        for(int j=1;j<=5;j++)  
            if(a.s[i][j]!=b.s[i][j])  
                return a.s[i][j]<b.s[i][j];     
}  

int main()    
{    
    freopen("prime3.in","r",stdin);     
    freopen("prime3.out","w",stdout);    
    cin>>sum>>m;  
    memset(IsOk,0,sizeof(IsOk));  
    num=0;   
    for(int i=10001;i<=99999;i++)  
        if(IsPrime(i) && EquSum(i))   
        {  
            a[++num]=i;  
            g[num][1]=i/10000; g[num][2]=(i/1000)%10;  
            g[num][3]=(i/100)%10; g[num][4]=(i/10)%10;  
            g[num][5]=i%10;  
            IsOk[i]=1;  
        }  
    int tep=0;  
    for(int i=1;i<=num;i++)  
        if(a[i]/10000!=tep)  
            h[++tep]=i;  
    
    h[10]=num+1;        
    times=0;  
    for(int i=h[m];i<h[m+1];i++)   
    {               
        s[1][1]=m;  s[1][2]=g[i][2];  
        s[1][3]=g[i][3];  s[1][4]=g[i][4];  
        s[1][5]=g[i][5];  
        if(s[1][1] && s[1][2] && s[1][3] && s[1][4] && s[1][5])      
        for(int j=h[m];j<h[m+1];j++)  
        {  
            s[2][1]=g[j][2];  s[3][1]=g[j][3];    
            s[4][1]=g[j][4];  s[5][1]=g[j][5];   
            b[1]=s[1][1]; b[2]=s[2][1]; b[3]=s[3][1];   
            b[4]=s[4][1]; b[5]=s[5][1];  
            if(s[2][1] && s[3][1] && s[4][1] && s[5][1])     
            for(int x=h[s[1][1]];x<h[s[1][1]+1];x++)  
            {  
                s[2][2]=g[x][2];  s[3][3]=g[x][3];  
                s[4][4]=g[x][4];  s[5][5]=g[x][5];  
                for(int y=h[s[5][1]];y<h[s[5][1]+1];y++)  
                    if(g[y][3]==s[3][3] && g[y][5]==s[1][5])  
                    {  
                          s[4][2]=g[y][2];  s[3][3]=g[y][3];      
                          s[2][4]=g[y][4];               
                          for(int z=h[s[2][1]];z<h[s[2][1]+1];z++)   
                              if(g[z][2]==s[2][2] && g[z][4]==s[2][4])     
                              {           
                                  s[2][3]=g[z][3]; s[2][5]=g[z][5];                                       
                                  getanswer(2);   
                              }  
                    }                   
            }  
        }   
    }   
    
    sort(ans+1,ans+1+times,cmp);   
      
    for(int x=1;x<=times;x++)  
    {  
        if(x!=1) cout<<endl;  
        for(int i=1;i<=5;i++)  
        {  
            for(int j=1;j<=5;j++) 
                cout<<ans[x].s[i][j];  
            cout<<endl;  
        }                     
    }  
    return 0;       
}     


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值