单词矩阵/贰五语言
题意:
对于包含字母A到Y各一次的单词S,将其从上到下从左到右写在一个5*5的矩阵中,如单
词ADJPTBEKQUCGLRVFINSWHMOXY写出来如下:
A D J P T
B E K Q U
C G L R V
F I N S W
H M O X Y
若该矩阵满足每一行每一列的字母都是字典序递增的则称S为优美的,如上述单词就是
优美的,而ADJPTBEGQUCKLRVFINSWHMOXY则不是(第二列不满足要求)。
Your Task
将所有优美的单词按字典序列出,从小到大编号1,2,……
请你完成以下两种任务:
1. 给定一个优美的单词,求其编号。
2. 给定一个编号,求对应的优美的单词。输入描述 Input Description第一行一个字母,W表示任务1,N表示任务2
若是任务1,第二行是一个优美的单词,否则第二行是一个正整数,表示某个优美的单
词的编号,保证该数不超过优美的单词的总数输出描述 Output Description一行,若是任务1,输出对应编号,否则输出对应的优美的单词
思路:
试图找规律 无果 所以就搜索啦 (在做之前就知道是一道搜索题qwq)
从小到达枚举字母来填方格时
对于每一行 左边的必须比右边先填(保证从左至右递增)
对于每一列 上面的必须比下面先填(保证从上至下递增)
So dfs(a,b,c,d,e,now) a表示第一行已经填了几个 b,c,d,e 同推 now表示现在要填第几个字母了(1表示A etc.)
带上记忆化搜索
那么就是f[a][b][c][d][e]表示第一行填了a个,第二行填b个,第三行填c个,第四行填d个,第5行填e个的满足题意的总方案数
现在我们具体来看两个问题:
1.给定序列求编号
就是求字典序比它小的合法序列个数再加1(加上它自己)
枚举第1-25位上的数的字母 每一位都不能超过题目给定序列对应位置上的字母 (不能等于!)
举个栗子:
我们要知道以BE开头的合法序列个数 那么搜第一位为A的序列列数
然后搜第一二位为BE的合法序列数 而不是搜第一位为B的合法序列数
然后把搜索到的方案数都加起来 输出答案记得加上1
2.给定编号求序列
同从小到大枚举第1-25位上的数字
假设 我们求第90个序列 现在枚举第二位(第一位必为A) 第二位为B时 有方案80种 ;为C时 有方案30种
那么要求的第90个序列的第二位一定为 C (方案总数刚好大于90)
以此类推 一位一位地确定下去
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 using namespace std; 6 int f[6][6][6][6][6],map[30],ans; 7 bool ck(int a,int b) {return (!map[a])||(map[a]==b);} 8 int dfs(int a,int b,int c,int d,int e,int now) 9 { 10 if(now==26) return 1; 11 int &tmp=f[a-1][b-1][c-1][d-1][e-1]; 12 if(tmp) return tmp; 13 if(a<=5 && ck(a,now)) tmp+=dfs(a+1,b,c,d,e,now+1); 14 if(b<a && ck(b+5,now)) tmp+=dfs(a,b+1,c,d,e,now+1); 15 if(c<b && ck(c+10,now)) tmp+=dfs(a,b,c+1,d,e,now+1); 16 if(d<c && ck(d+15,now)) tmp+=dfs(a,b,c,d+1,e,now+1); 17 if(e<d && ck(e+20,now)) tmp+=dfs(a,b,c,d,e+1,now+1); 18 return tmp; 19 } 20 int main() 21 { 22 char tp;scanf("%c",&tp); 23 if(tp=='W') { 24 string s;cin>>s; 25 for(register int i=1;i<=25;i++) 26 for(map[i]=1;map[i]<s[i-1]-'A'+1;map[i]++) { 27 memset(f,0,sizeof(f)); 28 ans+=dfs(1,1,1,1,1,1); 29 } 30 printf("%d",ans+1); //要+1 31 } 32 else { 33 int n;scanf("%d",&n); 34 for(register int i=1;i<=25;i++) 35 for(map[i]=1;map[i]<25;map[i]++) 36 { 37 memset(f,0,sizeof(f)); 38 int tmp=dfs(1,1,1,1,1,1); 39 if(tmp>=n) break ; 40 n-=tmp; //注意这里 41 } 42 for(register int i=1;i<=25;i++) printf("%c",map[i]-1+'A'); 43 } 44 return 0; 45 }