算法竞赛入门经典(紫书)第四章—— The Dole Queue UVA-133

14 篇文章 0 订阅

题意:
将 N 个数写在一个环上,顺时针数 k 个得到 x1,逆时针数 m 个得到 x2,将 x1 和 x2 输出,如果相同则只输出其中一个,输出后将其从环上删除。如此反复。

思路:
将环想象成数组,在数组上演示题意的过程,即有两个指针,一个向右移动,一个向左移动,当向右移动的指针移到结尾时再移动就会落在开头位置,当向左移动的指针移动到开头位置时,再移动就会移动到结尾处。
一开始我想的是用 vector 来存,这样可以直接删除,但是删除的逻辑比较麻烦,用数组直接做标记要来得简单许多。
我们可以将选中输出的数打上标记,这样就知道哪些数已经输出过了。
下面是对题目中样例的图解:

注意:
1. 输出时要用 “%3d”,不能用 ” %d”,我就在这个坑里摔了。。
2. 值得注意的是 x1 和 x2 是在输出后一起被删除的,而不是数出了 x1 后将 x1 删掉再去数 x2,注意这两者的不同。因为如果是后者的情况,数 x2 时如果会遇到 x1 则不会把 x1 算进去,由于 x1 已经被删掉了。

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
typedef long long LL;

int N, k, m;
int num[50];

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d%d%d", &N, &k, &m)==3 && N!=0 && k!=0 && m!=0){
        memset(num, 0, sizeof(num));
        for(int i=1; i<=N; i++){
            num[i] = i;
        }
        int p = 0;
        int q = N+1;
        int s = N;
        while(s){
            for(int i=0; i<k; i++){
                do{
                    p++;
                    if(p == N+1) p = 1;
                }while(num[p] == 0);
            }
            for(int i=0; i<m; i++){
                do{
                    q--;
                    if(q == 0) q = N;
                }while(num[q] == 0);
            }
            if(p != q){
                s -= 2;
                printf("%3d%3d", num[p], num[q]);
                num[p] = num[q] = 0;
            }else {
                s--;
                printf("%3d", num[p]);
                num[p] = 0;
            }

            if(s) printf(",");
            else printf("\n");
        }
    }
    return 0;
}

想看书上的源代码的话看这 (^▽^)
https://github.com/aoapc-book/aoapc-bac2nd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值