• 【置换群/模拟】NOIP2005-篝火晚会


    【问题描述】

    佳佳刚进高中,在军训的时候,由于佳佳吃苦耐劳,很快得到了教官的赏识,成为了“小教官”。在军训结束的那天晚上,佳佳被命令组织同学们进行篝火晚会。一共有n个同学,编号从1到n。一开始,同学们按照1,2,……,n的顺序坐成一圈,而实际上每个人都有两个最希望相邻的同学。如何下命令调整同学的次序,形成新的一个圈,使之符合同学们的意愿,成为摆在佳佳面前的一大难题。

    佳佳可向同学们下达命令,每一个命令的形式如下:

    (b1, b2,... bm -1, bm)

    这里m的值是由佳佳决定的,每次命令m的值都可以不同。这个命令的作用是移动编号是b1,b2,…… bm -1,bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。

    执行每个命令都需要一些代价。我们假定如果一个命令要移动m个人的位置,那么这个命令的代价就是m。我们需要佳佳用最少的总代价实现同学们的意愿,你能帮助佳佳吗?

    【输入文件】

    输入文件fire.in的第一行是一个整数n(3 <= n <= 50000),表示一共有n个同学。其后n行每行包括两个不同的正整数,以一个空格隔开,分别表示编号是1的同学最希望相邻的两个同学的编号,编号是2的同学最希望相邻的两个同学的编号,……,编号是n的同学最希望相邻的两个同学的编号。

    【输出文件】

    输出文件fire.out包括一行,这一行只包含一个整数,为最小的总代价。如果无论怎么调整都不能符合每个同学的愿望,则输出-1。

    【样例输入】

    4

    3 4

    4 3

    1 2

    1 2

    【样例输出】

    2

    【数据规模】

    对于30%的数据,n <= 1000;

    对于全部的数据,n <= 50000。

    【思路】

    假设起始状态为1...n。首先以第一个孩子为起点,模拟实现一个环的目标状态。此时如果建环过程中出现矛盾,直接输出-1;否则,一定可以通过若干次操作移动到目标状态。

    由于是环,起点位置可以改变,而且可以正序倒序两种方式。有以下几个结论:

    (1)两个数,如果它们和起始状态的差加上n再mod n的结果一样,说明它们共同移动某步,能移动到目标状态。看下面这个例子:

    起始状态:1 2 3 4 5

    目标状态:1 5 3 2 4

    差值:     0 3 0 -2 -1

    我们可以发现,对于5和2,(3%5=3),((-2+5)%5=3)相等。而这两个数向右移动两位,都可以到达目标状态。

    (2)每次移动一个价值,一定能使得一个数到达自己的目标状态。也就是说,有几个数与目标状态不对应,就需要消耗多少价值。

    由此我们可以明白:

    把差值(加n %n后)相同个数的最大值max求出来,然后把这几个数假设就在目标状态,那么移动需要的价值为n-max。因为环可以正反,正反各来一次即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 const int MAXN= 50000+500;
     8 int n;
     9 int want[MAXN][2];
    10 int q[MAXN];
    11 
    12 void init()
    13 {
    14     scanf("%d",&n);
    15     for (int i=0;i<n;i++)
    16     {
    17         scanf("%d%d",&want[i][0],&want[i][1]);
    18         want[i][0]--;
    19         want[i][1]--;
    20     }
    21 }
    22 
    23 int canmake()
    24 {
    25     q[0]=0;
    26     q[1]=want[0][0];
    27     for (int i=1;i<n-1;i++)
    28     {
    29         if (q[i-1]!=want[q[i]][0]) q[i+1]=want[q[i]][0];
    30             else if (q[i-1]!=want[q[i]][1]) q[i+1]=want[q[i]][1];
    31                 else return 0;
    32     }
    33     if (want[q[n-1]][0]!=0 && want[q[n-1]][1]!=0) return 0;
    34     for (int i=0;i<n;i++) cout<<q[i]<<endl;
    35     return 1;
    36 }
    37 
    38 void submain()
    39 {
    40     int ans=0;
    41     int appear[MAXN];
    42     int appear2[MAXN];
    43     memset(appear,0,sizeof(appear));
    44     memset(appear2,0,sizeof(appear2));
    45     for (int i=0;i<n;i++)
    46     {
    47         appear[(q[i]-i+n)%n]++;
    48         appear2[(q[i]+i-1)%n]++;
    49         if (appear[(q[i]-i+n)%n]>ans) ans=appear[(q[i]-i+n)%n];
    50         if (appear2[(q[i]+i-1)%n]>ans) ans=appear2[(q[i]+i-1)%n];
    51     }
    52     cout<<n-ans<<endl;
    53 }
    54 
    55 int main()
    56 {
    57     //freopen("fire9.in","r",stdin);
    58     //freopen("fire9.out","w",stdout);
    59     init();
    60     if (canmake()) submain();
    61         else cout<<-1<<endl;
    62     system("pause");
    63     return 0;
    64 }
  • 相关阅读:
    [古城子的房子] 贪心
    [小兔的棋盘] 组合数学
    [Triangle] Fibonacci+二分查找
    [Fibonacci] 矩阵快速幂
    [DP?]素数筛+Lucas定理+费马小定理
    react本地开发关闭eslint检查
    react 不同js文件里公用同一个变量
    js学习笔记
    node内存扩展,前端项目运行时报内存不足的错误
    Gitee码云通过WebHooks实现自动同步代码部署
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/4856697.html
Copyright © 2020-2023  润新知