单词矩阵/贰五语言

         problem   codevs 洛谷                                     

题意:

    对于包含字母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 }
View Code
光伴随的阴影
原文地址:https://www.cnblogs.com/forward777/p/10307268.html