zoukankan      html  css  js  c++  java
  • BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4985

    题目意思:有 n 个数,对于第 i 个数给出 σ(i) 的值。求出互不相交的循环的个数,并输出每个循环包含的数字。

         还是不太懂吧?反正比赛的时候我也没看懂 >__< !

         据说,这条题目用到了置换群 + 循环 的知识,黑书上 P246 有相应介绍。

         先来说明下这幅图的意思,搞明白题意就发现这条题是很好做的。

         

         它表示:σ(1) = 2, σ(2) = 5, σ(3) = 4, σ(4) = 3, and σ(5) = 1

         首先要知道为什么(1 2 5)和(3 4)要划分开来。我们从数字 1 ~ n 遍历,也就是上面的1 2 3 4 5 啦。那么遍历到 1 的时候,可以输出 1 (设一个vis数组,开始时全部为0,输出后vis[1] = 1),接着取σ(1) 也就是 2 啦,发现之前没有输出过(只输出了 1 而已)那就继续输出 2 啦(vis[2] = 1),接着算出σ(2) = 5,输出5(vis[5] = 1),然后发现 σ(5) = 1,但是vis[1] = 1已经输出过,所以不输出了。此时就发现1 2 5 是一个循环,就是说,通过σ(i)计算它只能在1 2 5 中取数。剩下的3 4 也是通过这样算的。

        黑书上有一段是这样介绍循环的:

        每个置换都可以写成若干互不相交的循环的乘积,两个循环(a1 a2 ...an) 和 (b1 b2 ...bn) 互不相交是指ai≠bj,i,j = 1, 2, ..., n。

        例如:

        

        是等于  (1 3 6)(2 5)(4)

        因为:1 —> 3 —> 6 —> 1 (循环了),2 —> 5 —> 2(循环了),4 —> 4 (自己循环自己)。

        

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 const int maxn = 1e5 + 5;
     7 int vis[maxn], a[maxn];
     8 
     9 int main()
    10 {
    11     int n;
    12     while (scanf("%d", &n) != EOF)
    13     {
    14         for (int i = 1; i <= n; i++)
    15             scanf("%d", &a[i]);
    16         memset(vis, 0, sizeof(vis));
    17         for (int i = 1; i <= n; i++)
    18         {
    19             if (vis[i])
    20                 continue;
    21             printf("(%d", i);  // 计算一个循环
    22             vis[i] = 1;
    23             int j = a[i];
    24             while (j != i)
    25             {
    26                 printf(" %d", j);
    27                 vis[j] = 1;
    28                 j = a[j];
    29             }
    30             printf(")");
    31         }
    32         printf("
    ");
    33     }
    34     return 0;
    35 }

       

        注意:上面的初始状态默认为 1 2 3 4...n 的

        对于一般情况的初始状态(不一定是1 2 3 4...n),给出对应的目标状态,要求分解为不相交的循环乘积的个数。例如初始状态为 8 4 5 3 2 7,而目标状态为 2 3 4 5 7 8,则可以分解为两个循环的乘积,即(8 2 7)(4 3 5).代码如下:

        

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 const int maxn = 1e5 + 5;
     7 int vis[maxn], a[maxn], b[maxn];
     8 
     9 int main()
    10 {
    11     int n;
    12     while (scanf("%d", &n) != EOF)
    13     {
    14         for (int i = 1; i <= n; i++)
    15             scanf("%d", &a[i]);
    16         int t;
    17         for (int i = 1; i <= n; i++)
    18         {
    19             scanf("%d", &t);
    20             b[a[i]] = t;
    21         }
    22     /*    for (int i = 1; i <= 8; i++)
    23             if (b[i])
    24                 printf("b[%d] = %d
    ", i, b[i]);
    25     */
    26         memset(vis, 0, sizeof(vis));
    27         for (int i = 1; i <= n; i++)
    28         {
    29             int k = a[i];
    30             if (vis[k])
    31                 continue;
    32             printf("(%d", k);  // 计算一个循环
    33             vis[k] = 1;
    34             int j = b[k];
    35             while (j != k)
    36             {
    37                 printf(" %d", j);
    38                 vis[j] = 1;
    39                 j = b[j];
    40             }
    41             printf(")");
    42         }
    43         printf("
    ");
    44 
    45     }
    46     return 0;
    47 }

        

  • 相关阅读:
    单例设计模式
    C#做窗体皮肤
    常用的数组的操作
    C#调试方法
    Timer
    程序对对象的字段的代码简写
    nginx upstream的几种配置方式
    ava如何实现系统监控、系统信息收集、sigar开源API的学习(转)
    vsftpd 被动模式与主动模式
    MySQL安装详解(V5.5 For Windows)
  • 原文地址:https://www.cnblogs.com/windysai/p/3951015.html
Copyright © 2011-2022 走看看