USACO6.4-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


题目大意:给出一个5*5的正方形和左上角的一个数字,要求每一行每一列每一对角线上的数字的和都等于输入的数,并且组成的五位数为质数,输出所有可能的5*5正方形。

算法:这是一道很麻烦的暴力题,朴素的枚举必定会超时,这时候需要调换枚举顺序,以及根据枚举的五位数的位置尽可能排除不可能的情况再枚举,要优化的地方还是比较多的,详见代码。

  1 #include <iostream>

  2 #include <memory.h>

  3 #include <stdio.h>

  4 #include <vector>

  5 #include <string>

  6 #include <algorithm>

  7 using namespace std;

  8 #define MAXN 100000

  9 #define R 0

 10 #define C 1

 11 

 12 

 13 void output(string str)

 14 {

 15     for(int i=0; i<str.length(); i++)

 16     {

 17         printf("%c",str[i]);

 18         if(i%5==4)

 19             printf("\n");

 20     }

 21 }

 22 

 23 int getDigSum(int x)

 24 {

 25     int sum=0;

 26     while(x!=0)

 27     {

 28         sum+=x%10;

 29         x/=10;

 30     }

 31     return sum;

 32 }

 33 

 34 bool allDigOdd(int x)

 35 {

 36     while(x!=0)

 37     {

 38         int dig=x%10;

 39         if(dig%2==0)

 40             return false;

 41         x/=10;

 42     }

 43     return true;

 44 }

 45 

 46 bool allNoZero(int x)

 47 {

 48     while(x!=0)

 49     {

 50         int dig=x%10;

 51         if(dig==0)

 52             return false;

 53         x/=10;

 54     }

 55     return true;

 56 }

 57 

 58 int isPrime[MAXN+10],primeDig[MAXN+10][5];

 59 

 60 int a[5][5]= {0},goalSum=0,st;

 61 vector<int> primelist[100]; // 以d[ij]表示以i开头,j结尾的字符串

 62 vector<int> primelistMid[1000]; // 以d[ijk]表示以i开头,j为百位,k结尾的字符串

 63 vector<int> primelistOdd[100]; // 各位上的数都为奇数

 64 vector<int> primelistnozero[100]; // 各位上都没有0

 65 vector<string> res;

 66 

 67 int isprime(int type,int num)

 68 {

 69 

 70     int sum=0;

 71     if(type==R)

 72     {

 73         for(int i=0; i<5; i++)

 74             sum=sum*10+a[num][i];

 75     }

 76     else

 77     {

 78         for(int i=0; i<5; i++)

 79             sum=sum*10+a[i][num];

 80     }

 81     return isPrime[sum];

 82 }

 83 

 84 void add()

 85 {

 86     string str;

 87     for(int i=0; i<5; i++)

 88         for(int j=0; j<5; j++)

 89         {

 90             str+='0'+a[i][j];

 91         }

 92     res.push_back(str);

 93 }

 94 

 95 void initA()

 96 {

 97     for(int i=0; i<5; i++)

 98         for(int j=0; j<5; j++)

 99             a[i][j]=100;

100 }

101 

102 int main()

103 {

104     freopen("prime3.in","r",stdin);

105     freopen("prime3.out","w",stdout);

106 

107     initA();

108 

109     // 求素数表

110     memset(isPrime,-1,sizeof isPrime);

111     for(int i=2; i<=MAXN; i++)

112         if(isPrime[i])

113             for(long long j=(long long)i*i; j<=MAXN; j+=i)

114                 isPrime[j]=false;

115 

116 

117     cin>>goalSum>>st;

118 

119     for(int i=10000; i<MAXN; i++)

120         if(isPrime[i] && getDigSum(i)!=goalSum)

121             isPrime[i]=0;

122 

123     for(int i=10000; i<MAXN; i++)

124         if(isPrime[i])

125         {

126             int x=i;

127             for(int j=0; j<5; j++)

128             {

129                 primeDig[i][4-j]=x%10;

130                 x/=10;

131             }

132             primelist[i/10000*10+i%10].push_back(i);

133             primelistMid[i/10000*100+(i%1000)/100*10+i%10].push_back(i);

134         }

135 

136     // 各位上都为奇数

137     for(int i=10000; i<MAXN; i++)

138         if(isPrime[i] && allDigOdd(i))

139             primelistOdd[i/10000*10+i%10].push_back(i);

140 

141     // 各位上都为非0

142     for(int i=10000; i<MAXN; i++)

143         if(isPrime[i] && allNoZero(i))

144             primelistnozero[i/10000*10+i%10].push_back(i);

145 

146     bool found=false;

147 

148     a[0][0]=st;

149     // 枚举 先是右下方数字

150     for(a[4][4]=1; a[4][4]<=9; a[4][4]+=2)

151     {

152         // 枚举左下方数字

153         for(a[4][0]=1; a[4][0]<=9; a[4][0]+=2)

154         {

155             // 枚举右上方数字

156             for(a[0][4]=1; a[0][4]<=9; a[0][4]+=2)

157             {

158                 //填充左边质数

159                 for(int i=0; i<primelistnozero[st*10+a[4][0]].size(); i++)

160                 {

161                     for(int j=0; j<5; j++)

162                         a[j][0]=primeDig[primelistnozero[st*10+a[4][0]][i]][j];

163 

164                     // 填充上边质数

165                     for(int ii=0; ii<primelistnozero[st*10+a[0][4]].size(); ii++)

166                     {

167                         for(int j=0; j<5; j++)

168                             a[0][j]=primeDig[primelistnozero[st*10+a[0][4]][ii]][j];

169 

170 

171                         // 填充下边质数

172                         for(int iii=0; iii<primelistOdd[a[4][0]*10+a[4][4]].size(); iii++)

173                         {

174                             for(int j=0; j<5; j++)

175                                 a[4][j]=primeDig[primelistOdd[a[4][0]*10+a[4][4]][iii]][j];

176 

177 

178                             //填充右边质数

179                             for(int iiii=0; iiii<primelistOdd[a[0][4]*10+a[4][4]].size(); iiii++)

180                             {

181                                 for(int j=0; j<5; j++)

182                                     a[j][4]=primeDig[primelistOdd[a[0][4]*10+a[4][4]][iiii]][j];

183 

184 

185                                 // 填充中间一点

186                                 for(a[2][2]=0; a[2][2]<=9; a[2][2]++)

187                                 {

188 

189                                     // 填充主对角线

190                                     for(int k=0; k<primelistMid[st*100+a[2][2]*10+a[4][4]].size(); k++)

191                                     {

192                                         a[1][1]=primeDig[primelistMid[st*100+a[2][2]*10+a[4][4]][k]][1];

193                                         a[3][3]=primeDig[primelistMid[st*100+a[2][2]*10+a[4][4]][k]][3];

194 

195                                         // 填充辅对角线

196                                         for(int l=0; l<primelistMid[a[4][0]*100+a[2][2]*10+a[0][4]].size(); l++)

197                                         {

198                                             a[3][1]=primeDig[primelistMid[a[4][0]*100+a[2][2]*10+a[0][4]][l]][1];

199                                             a[1][3]=primeDig[primelistMid[a[4][0]*100+a[2][2]*10+a[0][4]][l]][3];

200 

201                                             int a12=goalSum-(a[1][0]+a[1][1]+a[1][3]+a[1][4]);

202                                             int a21=goalSum-(a[0][1]+a[1][1]+a[3][1]+a[4][1]);

203                                             int a23=goalSum-(a[0][3]+a[1][3]+a[3][3]+a[4][3]);

204                                             int a32=goalSum-(a[3][0]+a[3][1]+a[3][3]+a[3][4]);

205                                             a[1][2]=a12;

206                                             a[2][1]=a21;

207                                             a[2][3]=a23;

208                                             a[3][2]=a32;

209                                             if(a12>=0 && a12<10 && a21>=0 && a21<10 && a23>=0 && a23<10 && a32>=0 && a32<10

210                                                     && isprime(R,1) && isprime(R,2) && isprime(R,3)

211                                                     && isprime(C,1) && isprime(C,2) && isprime(C,3))

212                                             {

213                                                 found=true;

214                                                 add();

215                                             }

216                                         }

217 

218                                     }

219                                 }

220 

221                             }

222                         }

223                     }

224                 }

225             }

226         }

227     }

228 

229     sort(res.begin(),res.end());

230     bool first=true;

231     for(int i=0; i<res.size(); i++)

232     {

233         if(!first)

234         {

235             cout<<endl;

236         }

237         first=false;

238         output(res[i]);

239     }

240 

241     if(!found)

242         printf("NONE\n");

243     return 0;

244 }

 



                            

你可能感兴趣的:(USACO)