zoukankan      html  css  js  c++  java
  • SCAU 9503 懒人选座位

    9503 懒人选座位

    时间限制:500MS  内存限制:65535K 提交次数:0 通过次数:0

    题型: 编程题   语言: 无限制

    Description

        在ACM混了一年之后,我终于有机会在新生赛出题了。然后我瞬间出了一道题。
        (好吧,我承认,我只是翻译了原题而已╮(╯▽╰)╭) 
        发过去给lyd,然后马上被鄙视了:“这么简单的题目?”
        哎,没办法啊,过去一年我就是切水题过来的~~ 
        其实我个人认为这题还是挺有趣的……水水更健康吗……大家一起来切水题吧! 
        相信大家都有这样的体验吧:课室里每行座位间的间距都很小,上课的时候,早到的同学都要侧身或者站起来,让其他同学坐进去里面。 ╮(╯▽╰)╭ 我是一个很懒的人,假如我是第一个到场,我希望选了座位之后,侧身让位的次数能够尽量地少……
        现在有一排n个空座位,从左到右分别编号1 ~ n。 然后其他同学都会选定一个座位然后走进去,并且进去的方位(左边or右边)服从以下的规定:
        1.	选择途经人数最少的方向进入 
                  ①	②	我	③	④	⑤	⑥	
    	比如第二个到的同学选定了3号座位,他会选择从右边进入,我不用让位。
        2.	当两端途经的人数一样时,选择靠近自己座位的那边进入。
                  ①	②	我	③	④	⑤	有人	⑥	
        比如第三个到的同学选择坐3号座位,他会从左边进入,然后我要让位。
        3.	都一样时,随机选进入方位。
        现在的问题是,当我选择坐第k个座位后,我想知道在最坏的情况下,要侧身让位多少次?
    

    Input

        有若干组数据,以EOF判定结束。
        每组数据第一行有两个整形n(1~ 30)和q(1~30)。分别表示座位数和查询次数。接下来一行有q个整型。k1,k2……kq,分别表示我选择坐第k个座位。数据以空格分隔。
    

    Output

        每组数据一行,对于每次查询,输出一个结果,以空格分隔。

    Sample Input

    4 4
    1 2 3 4
    5 5
    1 2 3 4 5
    

    Sample Output

    1 0 0 1
    2 1 0 1 2
    

    Hint

        四个座位的时候,我选定座位①后,若第二个人选了③or④,当第三个人选②,我就要让位一次,这个是最坏的情况。
        EOF结束即是数据读入以文件结束符结束。即输入输出类似如下(当然变量名啥的不必一样,VC下按ctrl+z 然后
        回车可结束程序):
        while(scanf("%d%d",&n,&q)!=EOF)
        {
            for(i=1;i<=q;i++)
            scanf("%d",&act[i]);
            ……
            ……
            printf("%d\n",answer);
        }

    Source

    sleepiforest

    Provider

    a470086609

     

     #include<stdio.h>
     #include<string.h>
     int main()
     {
         int i, n, q, act[32], temp;
         while(scanf("%d%d",&n,&q) != EOF)
        {
            memset(act, 0, sizeof(act));
            for(i=0; i < q; i++)
            {
                scanf("%d",&temp);
                if(temp>n/2) act[i] = n+1-temp;
                else act[i] = temp;
            }
            if(n == 1 || n == 2)
            {
                for(i=0; i<q; ++i)
                 if(!i) printf("0");
                 else printf(" 0");
            }
            
            else if(n == 3)
            {
                for(i=0; i<q; ++i)
                if(act[i] == 1 && i == 0) printf("1");
                else if(act[i] == 1) printf(" 1");
                else if(i == 0) printf("0");
                else printf(" 0");
            }
            
            else
            {
                for(i=0; i<q; ++i)
                {
                    temp = n - act[i] - 2;
                    if(i == 0) printf("%d", temp);
                    else printf(" %d", temp);
                }
            }
            
            printf("\n");
        }
         return 0;
     } 

    解题报告:
    1y, 不过还是花了我差不多两个小时的时间……/遗憾

    原则很重要!

    1. 选择途径人数最少的方向进入

    2. 两端人数一样的时候,选择靠近的方向进入 (最坏的情况是选择永远靠近懒人的座位)

    3. 都一样时,随机选取进入的方向 (选择的座位应该说是能让懒人让座或能间接让座的位置)

    拿几组数据模拟演算一遍,其中的规律就能够发现了

           首先要处理对称的情况,只需考虑懒人所坐位置为n一半的情况就行;  现假设懒人一直坐在偏向左的位置(极端为n为奇数时,懒人最右也只能坐中间),此时不管懒人坐在哪里,(记住,你的目的是让懒人尽量地让位)你首先要做的就是先在右边(n/2 ~n)的位置处先找个人(除懒人外第一个人,记为P1)坐下,此刻才可以跟懒人“抗衡”。此时如果懒人距离这一排座位的中间位置(如果n是奇数,那就是中间位置,如果是偶数,那就是n/2-1的地方),根据第二条原则,你是不是想再加一个人放到懒人和中间位置之间的座位,以此让懒人能够让位呢?但我不这么做,尽管最后其他人坐这些位置时还是让懒人站起来了。

          应该尽可能地用第一条原则,此时P1正在与懒人抗衡,如果你将P2安排在P1的旁边,不管左边还是右边,总之紧接着P1,此时第三个人P3来了,你要把它紧紧贴身安排在(P1P2)的左边,这时P3该怎么进去呢? P3必须从懒人那边进去,因为根据第一条原则:选择途经人数最少的方向进入, 再来P4、P5……直到把懒人跟PN之间的位置坐满,此时懒人让位的次数也达到了最大,不一定,如果一开始没把P1P2安排到最右边的座位……

         上面的情况只适应与n>=4的情况,至于n = 1, 2, 3的情况另外处理。

  • 相关阅读:
    UVALive 8519 Arrangement for Contests 2017西安区域赛H 贪心+线段树优化
    UVALive 8513 lovers 2017 西安区域赛 B 贪心+multiset
    JAVA导出EXCEL——POI(转)
    Oracle导入导出——windows命令行形式
    miniUI ExcelExport导出JAVA实现
    JSONObject遍历获取键值
    wrong number of arguments
    JAVA批量修改文件名
    miniUI DataGrid编辑后事件代码示例
    oracle10g没有行列转换函数的替代方法(转)
  • 原文地址:https://www.cnblogs.com/liaoguifa/p/2783137.html
Copyright © 2011-2022 走看看