USACO Section 4.3 The Primes - 好恶心的搜索

24 篇文章 0 订阅


    看题目名字是质数..以为是水题...读完题目更觉得是水题..范围这么小..先打个质数表不就秒了么~~结果...纠结了一下午一晚上..写了150行代码终于整出来了...确实这题就是搜索..但要讲究策略.

    1.先打表是必须的..注意的是这个表打得是既是素数且每位相加又是所要求的数的5位数..并且了为避免重复计算..在这里就可以把每个符合要求的数给拆分好记录...

    2.我这里不论是确定行还是确定列还是确定对角线..都是直接确定一整行或者一整列或一整对角线..也就是直接是找个五位数全部天上去...因为已经有打好的表..并且做表时就能保证有序..大大减少了无意义的搜索试探.. 

    3.搜索顺序...先确定最上一条..再是最左一条..再是两个对角线..再是第二行...然后再搜索枚举2,3,4,5列~~至于为什么是这个顺序..我是不断尝试出来的..特别是在枚举列之前先确定住第二行提高了很多效率...

       先确定最左边一条和最上面一条是因为输入时给的就是左上角.正好从这个点展开.并且题目要求必须是"真正的五位数"..也就是说最上面一条河最左边一条上不能出现0

       提前确定了前两行的好处是在搜索2,3,4,5,列时前两行的值已经确定..那么就可以根据这两行的确定值剪掉枚举出得前两行不等的情况...但若提前确定了前三行..效果却比较差..不明原因..  

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

   我就主要是上述五种方法...第十个点好危险...涉险AC~~~


Program:

/*  
ID: zzyzzy12   
LANG: C++   
TASK: prime3
*/      
#include<iostream>      
#include<istream>  
#include<stdio.h>      
#include<string.h>      
#include<math.h>      
#include<stack>
#include<map>
#include<algorithm>      
#include<queue>   
#define oo 1000000000  
#define ll long long  
#define pi (atan(2)+atan(0.5))*2 
using namespace std; 
struct node
{
      int s[6][6];      
}ans[1005];
bool IsPrime(int k)
{
      int i;
      for (i=2;i*i<=k;i++)
         if (k%i==0) return false;
      return true;    
}
int num,a[1001],sum,m,s[6][6],times,h[11],b[8],g[1001][6];
bool IsOk[100005];
void getanswer(int p)
{
      int i,j,k; 
      if (p>5)
      {  
            for (i=3;i<=5;i++)
            {
                  k=0;
                  for (j=1;j<=5;j++)  
                      k=k*10+s[i][j]; 
                  if (b[i]!=sum || !IsOk[k]) return;      
            }
            times++; 
            for (i=1;i<=5;i++)
               for (j=1;j<=5;j++) ans[times].s[i][j]=s[i][j];  
            return;  
      }   
      for (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 true;
      return false;
}
bool cmp(node a,node b)
{
      int i,j;
      for (i=1;i<=5;i++)
         for (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);  
      scanf("%d%d",&sum,&m);
      int i,j,k,x,y,z;
      memset(IsOk,false,sizeof(IsOk));
      num=0; 
      for (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]=true;
          }
      j=0;
      for (i=1;i<=num;i++)
         if (a[i]/10000!=j)
            h[++j]=i;
      h[10]=num+1;      
      times=0;
      for (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 (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 (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 (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 (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 (x=1;x<=times;x++)
      {
            if (x!=1) printf("\n");
            for (i=1;i<=5;i++)
            {
                  for (j=1;j<=5;j++) printf("%d",ans[x].s[i][j]);
                  printf("\n");
            }                   
      }
      return 0;     
}   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值