USACO6.4.1 The Primes(prime3)
2015-02-06 17:35
197 查看
搜索题,但是好麻烦,各种的优化才涉险过了
1.先打表是必须的:这个表是既是素数且每位相加又是所要求的数的5位数,并且为避免重复计算,可以把每个符合要求的数给拆分好记录
2.确定行,列,对角线,直接确定一整行或者一整列或一整对角线,也就是直接是找个五位数全部添上去(因为已经有打好的有序的表),减少了无意义的搜索试探
3.搜索顺序:最上一条—最左一条—两个对角线—第二行—枚举2,3,4,5列(为什么是这个顺序,我不知道,可能是数据的影响吧,特别是在枚举列之前先确定第二行很有用)
先确定最左和最上是因为输入时给的就是左上角,正好从这个点展开,并且题目要求必须是"真正的五位数",也就是说最上和最左不能出现0
提前确定前两行的好处是在搜索2,3,4,5,列时前两行的值已经确定,就可以根据这两行的确定值剪掉枚举出得前两行不等的情况,但若提前确定了前三行,效果差了,不知道为什么
4.在枚举2,3,4,5列时,用数组记录3,4,5行的和情况,若在中途这其中有和大于所要求的了,直接剪掉
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; }
相关文章推荐
- [USACO 6.4.1] The Primes
- [USACO1.5]回文质数 Prime Palindromes
- 这压缩,太强了![USACO1.3]牛式 Prime Cryptarithm
- USACO 1.4 Prime Palindromes
- usaco Superprime Rib
- usaco 1.3 Prime Cryptarithm
- USACO:Prime Palindromes
- USACO 1.5 Prime Palindromes (打表查询)
- USACO Section 1.3 Prime Cryptarithm
- USACO 1.3 Prime Cryptarithm (crypt1)
- USACO - Chapter1 Section 1.3 - Prime Cryptarithm
- usaco pprime
- [USACO]Section 1.3 Prime Cryptarithm
- USACO 1.3 Prime Cryptarithm
- USACO1.52 Prime Palindromes
- USACO1.5Superprime Rid[附带关于素数算法时间测试]
- USACO Section 1.5 Prime Palindromes(回文数+素数)
- usaco Prime Cryptarithm
- USACO Prime Palindroms
- 【USACO1.3】牛式 Prime Cryptarithm