zoukankan      html  css  js  c++  java
  • UVA 133 The Dole Queue(报数问题)

    题意:一个长度为N的循环队列,一个人从1号开始逆时针开始数数,第K个出列,一个人从第N个人开始顺时针数数,第M个出列,选到的两个人要同时出列(以不影响另一个人数数),选到同一个人就那个人出列。

    思路:用数组来操作,详情见代码吧。

    #include <iostream>
    #include <stdio.h>
    #include <string>
    
    /*
    用数组存储序号,从左到右依次为1~n。
    逆时针相当于从左往右依次数,大于n再从1开始,用right作为指针。
    顺时针相当于从右往左依次数,小于1再从n开始,用left作为指针。
    */
    using namespace std;
    const int maxn=25;
    int p[maxn]; //存储一开始的序列
    int n,k,m;
    
    int main()
    {
        while(scanf("%d%d%d",&n,&k,&m)!=EOF){
            if(n==0&&k==0&&m==0)
                break;
            int first=1;
            for(int i=0;i<=n;i++)
                p[i]=i+1;
            int left=n-1,right=0;
            do{
                //n为剩余人的个数,下面是计算此次被数到的人的位置
                right=(right+n+k-1)%n;
                //从left开始往左数m个,相当于从left开始往右数n-(m-1)个
                left=((left+n-(m-1))%n+n)%n;  //注意这里很有可能会出现负数,所以加n再模一次
                if(left==right){
                    if(first)
                        printf("%3d",p[left]);
                    else
                        printf(",%3d",p[left]);
                    first=0;
                    for(int i=left;i<n;i++)
                        p[i]=p[i+1];
                    //因为left是往左移的,后面的数往左移动,指针也要往左移动,使left指向出列的那个人的前一个人
                    //而由于right是往右数的,后面的数往左移动,right自动指向后一个(即出列的那个人的后一个),所以不需要变动
                    left--;
                    if(left<0 && n>1)
                        left=(left+n-1)%(n-1);
                    n--;
                }
                else{
                    if(first)
                        printf("%3d%3d",p[right],p[left]);
                    else
                        printf(",%3d%3d",p[right],p[left]);
                    first=0;
                    //left指针在right之前
                    if(left<right){
                        for(int i=right;i<n;i++)
                            p[i]=p[i+1];
                        for(int i=left;i<n-1;i++)
                            p[i]=p[i+1];
                        /*
                          right后面的数都往左移动1次
                          left后面的数都往左移动2次,
                          由于right指针是往右移动的,所以为了指向出列的人的后一个,right要减1
                          left指针则是往左移动的,这里要往左移动1格,指向出列的人的前一个。
                        */
                        right--;
                        if(right<0 && n>2)
                        right=(right+n-2)%(n-2);
                        left--;
                        if(left<0 && n>2)
                        left=(left+n-2)%(n-2);
                    }
                    //left指针在right之后
                    else{
                        for(int i=left;i<n;i++)
                            p[i]=p[i+1];
                        for(int i=right;i<n-1;i++)
                            p[i]=p[i+1];
                        /*left指针后面的数都往左移动1次
                          right指针后面的数都往左移动2次,
                          由于right指针是往右移动的,当后面的数往左移动,right自动指向出列的人的后一个,所以不需要变动。
                          left指针则是往左移动的,这里要往左移动2格,指向出列的人的前一个。
                        */
                        left-=2;
                        if(left<0 && n>2)
                        left=(left+n-2)%(n-2);
                    }
                    n-=2;
                }
            }while(n);
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    披萨
    扩展gcd
    LOJ6276 果树
    BZOJ 2038: [2009国家集训队]小Z的袜子(hose) | 莫队
    BZOJ 3052: [wc2013]糖果公园 | 树上莫队
    BZOJ 1878: [SDOI2009]HH的项链 | 莫队
    BZOJ 2453 维护队列 | 分块
    BZOJ 2821: 作诗(Poetize) | 分块
    BZOJ 2653 middle | 主席树
    BZOJ 1901: Zju2112 Dynamic Rankings | 带修改主席树
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3337755.html
Copyright © 2011-2022 走看看