zoukankan      html  css  js  c++  java
  • ACM数论之旅12---康托展开((*゚▽゚*)装甲展开,主推进器启动,倒计时3,2,1......)

    在我们做题中,搜索也好,动态规划也好,我们往往有时候需要用一个数字表示一种状态

    比如有8个灯泡排成一排,如果你用0和1表示灯泡的发光情况

    那么一排灯泡就可以转换为一个二进制数字了

    比如

    01100110 = 102

    11110000 = 240

    10101010 = 170

    通过这些十进制数,只要把他们展开,我们就知道灯泡的状态了

    如果这题是一个动态规划题

    然后我们就拿这些数字做一些转移了,

    比如dp[102],dp[240],dp[170]等等

    这对题目很有帮助

    上面讲的那些就是所谓的状态压缩了,须知详细的状态压缩可以去百度

    或者有机会我自己去写一篇博客(这是flag(/TДT)/)

    那对于有些题,我们即使状态压缩后,数字太大,数组都开不下,麻烦的题目(/TДT)/

    这些题目也要看情况,比如我接下来要讲的康托展开

    康托展开经典题:hdu 1430

    http://acm.hdu.edu.cn/showproblem.php?pid=1430

    在魔方风靡全球之后不久,Rubik先生发明了它的简化版——魔板。魔板由8个同样大小的方块组成,每个方块颜色均不相同,可用数字1-8分别表示。任一时刻魔板的状态可用方块的颜色序列表示:从魔板的左上角开始,按顺时针方向依次写下各方块的颜色代号,所得到的数字序列即可表示此时魔板的状态。例如,序列(1,2,3,4,5,6,7,8)表示魔板状态为:

    1 2 3 4
    8 7 6 5

    对于魔板,可施加三种不同的操作,具体操作方法如下:

    A: 上下两行互换,如上图可变换为状态87654321
    B: 每行同时循环右移一格,如上图可变换为41236785
    C: 中间4个方块顺时针旋转一格,如上图可变换为17245368

    给你魔板的初始状态与目标状态,请给出由初态到目态变换数最少的变换步骤,若有多种变换方案则取字典序最小的那种。

    Input
    每组测试数据包括两行,分别代表魔板的初态与目态。
     
    Output
    对每组测试数据输出满足题意的变换步骤。
     
    Sample Input
    12345678
    17245368
    12345678
    82754631
     
    Sample Output
    C
    AC

    我们看这题,总共有8个数字,1~8,假如我们把他们看成0~7

    那么每个数字可以转换为一个3位二进制

    0:000

    1:001

    2:010

    3:011

    4:100

    5:101

    6:110

    7:111

    然后12345678这个状态我们可以表示为二进制000001010011100101110111,总共3*8=24位,

    2^24 = 16777216,数组根本开不下啊

    这时,我们发现了,有一些状态,根本没有用到,因为这题已经规定了有8个数字,每个数字只出现一次

    比如000000000000000000000000这个状态,你说可能出现吗?(o ° ω ° O )

    这个时候,康托就对这种题目做了研究(o ° ω ° O )

    这种每个数字只出现一次的问题的所以情况,总共才n!个情况(这个问题叫做全排列)

    康托的一套算法可以正好产生n!个数字

    比如:

    123  ->  0

    132  ->  1

    213  ->  2

    231  ->  3

    312  ->  4

    321  ->  5

    这是如何做到的(/≥▽≤/)

    在峰神的博客里面有很好的解释(对不起了峰神≖‿≖✧,拿过来抄一下)

    康托展开1

    康托展开2

    (/≥▽≤/)好神奇

    于是乎,康托展开模板:

     1 void cantor(int s[], LL num, int k){//康托展开,把一个数字num展开成一个数组s,k是数组长度
     2     int t;
     3     bool h[k];//0到k-1,表示是否出现过 
     4     memset(h, 0, sizeof(h)); 
     5     for(int i = 0; i < k; i ++){
     6         t = num / fac[k-i-1];
     7         num = num % fac[k-i-1];
     8         for(int j = 0, pos = 0; ; j ++, pos ++){
     9             if(h[pos]) j --;
    10             if(j == t){
    11                 h[pos] = true;
    12                 s[i] = pos + 1;
    13                 break;
    14             }
    15         }
    16     }
    17 }
    18 void inv_cantor(int s[], LL &num, int k){//康托逆展开,把一个数组s换算成一个数字num 
    19     int cnt;
    20     num = 0;
    21     for(int i = 0; i < k; i ++){
    22         cnt = 0;
    23         for(int j = i + 1; j < k; j ++){
    24             if(s[i] > s[j]) cnt ++;//判断几个数小于它
    25         }
    26         num += fac[k-i-1] * cnt;
    27     }
    28 }

    付上AC代码:

    (这代码我在杭电上用c++交竟然CE了,g++就没问题,CE的内容是我的那个模板,说什么不能bool h[k]这样声明类型,c++小心眼,这有什么关系嘛(´・ω・)ノ,我还只是个孩子)

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<string>
     5 #include<algorithm>
     6 #include<queue>
     7 using namespace std; 
     8 typedef long long LL;
     9 const int N = 8;
    10 queue <LL> que;
    11 string ans[50000];
    12 char str1[10], str2[10];
    13 bool vis[50000];
    14 
    15 int map[10];//映射
    16 int num[10];
    17  
    18 LL fac[N];//阶乘
    19 void change(int s[], int o){//o分别是0,1,2,表示ABC三种变化
    20     switch(o){
    21         case 0:
    22             for(int i = 0; i < 4; i ++) swap(s[i], s[8-i-1]);
    23             break;
    24         case 1:
    25             for(int i = 3; i >= 1; i --) swap(s[i], s[i-1]);
    26             for(int i = 4; i < 7; i ++) swap(s[i], s[i+1]);
    27             break;
    28         case 2:
    29             swap(s[1], s[6]);
    30             swap(s[6], s[5]);
    31             swap(s[5], s[2]);    
    32             break;
    33     } 
    34 } 
    35 void cantor(int s[], LL num, int k){//康托展开,把一个数字num展开成一个数组s,k是数组长度
    36     int t;
    37     bool h[k];//0到k-1,表示是否出现过 
    38     memset(h, 0, sizeof(h)); 
    39     for(int i = 0; i < k; i ++){
    40         t = num / fac[k-i-1];
    41         num = num % fac[k-i-1];
    42         for(int j = 0, pos = 0; ; j ++, pos ++){
    43             if(h[pos]) j --;
    44             if(j == t){
    45                 h[pos] = true;
    46                 s[i] = pos + 1;
    47                 break;
    48             }
    49         }
    50     }
    51 }
    52 void inv_cantor(int s[], LL &num, int k){//康托逆展开,把一个数组s换算成一个数字num 
    53     int cnt;
    54     num = 0;
    55     for(int i = 0; i < k; i ++){
    56         cnt = 0;
    57         for(int j = i + 1; j < k; j ++){
    58             if(s[i] > s[j]) cnt ++;//判断几个数小于它
    59         }
    60         num += fac[k-i-1] * cnt;
    61     }
    62 }
    63 void init(){
    64     fac[0] = 1;
    65     for(int i = 1; i < N; i ++) fac[i] = fac[i-1] * i;
    66     int a[8], b[8];
    67     LL temp, temp2;
    68     que.push(0);
    69     vis[0] = true;
    70     while(!que.empty()){
    71         LL temp = que.front(); que.pop();
    72         cantor(a, temp, 8);
    73         for(int i = 0; i < 3; i ++){
    74             copy(a, a+8, b);
    75             change(b, i);
    76             inv_cantor(b, temp2, 8);
    77             if(!vis[temp2]){
    78                 que.push(temp2);
    79                 vis[temp2] = true;
    80                 ans[temp2] = ans[temp] + (char)('A' + i);
    81             }
    82         }
    83     }
    84 }
    85 int main(){
    86     init();
    87     while(~scanf("%s", str1)){
    88         scanf("%s", str2);
    89         //先把所有初始状态都转换成12345678
    90         //最终状态根据初始状态的转换而转换 
    91         //这样只要一次预处理就可以解决问题了 
    92         for(int i = 0; i < 8; i ++) map[str1[i] - '0'] = i + 1;
    93         for(int i = 0; i < 8; i ++) num[i] = map[str2[i] - '0'];
    94         LL temp;
    95         inv_cantor(num, temp, 8);
    96         cout << ans[temp] << endl;
    97     }
    98 }
    View Code

    宇宙我来啦~(≧▽≦)/~

  • 相关阅读:
    [SSRS] Use Enum values in filter expressions Dynamics 365 Finance and Operation
    Power shell deploy all SSRS report d365 FO
    display method in Dynamics 365 FO
    How To Debug Dynamics 365 Finance and Operation
    Computed columns and virtual fields in data entities Dynamics 365
    Azure DevOps for Power Platform Build Pipeline
    Create readonly entities that expose financial dimensions Dynamics 365
    Dataentity call stack dynamics 365
    Dynamics 365 FO extension
    Use singletenant servertoserver authentication PowerApps
  • 原文地址:https://www.cnblogs.com/linyujun/p/5205760.html
Copyright © 2011-2022 走看看