Uva 133 The Dole Queue

题目意思:有N份申请表围城一圈,编号为逆时针编号,有两个人一个从逆时针走k步,另一个人顺时针走m,然后就有两个人所对应的申请书的编号,如果两个人走到同一个编号那么只要删除一个就好,如果不同删除两个,知道元素为空。

解题思路:我们很容易想到用循环队列来做,但是实现起来真的有点复杂,我们可以利用数组模拟,开两个数组,分别存储编号值,再开两个数组用来表示是否该位置被删除

begin1  begin2表示两个人的下一位置

注意事项:如果下一位置被删除了,那么我们要继续向下,就是要走有申请书的位置K步(或第二个人的m步);

代码1(数组模拟过程)

#include <iostream>
#include <stack>
#include <map>
using namespace std;

int p1[25] , p2[25];//两个数组分别存储两个人走的方向的编号,例如 p1={1,2....n} , p2={n , n-1 ...1};
int mark1[25] , mark2[25];//两个数组标记是否被删除,0没有,1有
int n, m ,k;
int begin1 , begin2;//分别表示两个人的下一步开始位置,初始化为全为1

//初始化函数
void init(){
    int i , j;
    memset(p1 , 0 , sizeof(p1));
    memset(p2 , 0 , sizeof(p2));
    memset(mark1 , 0 , sizeof(mark1));
    memset(mark2 , 0 , sizeof(mark2));
    //编号的赋值
    for(i = 1 ; i <= n ; i++){
        p1[i] = i;
        p2[i] = n-i+1;
    }
}

//第一个人走的函数
int find1(int begin , int n , int k){
    int count = 0;
    while(count < k){
        if(begin == n + 1)//如果超过n从新变成1
            begin = 1;
        if(mark1[begin] == 0){//如果该位置没被删除
            count++;//向前走一步
            if(count == k)//如果走了k步就退出
                break;
        }
        begin++;//begin每一次都要加,因为如果下一个是被删除了则继续向下
    }
    return begin;
}

//第二个人走的函数(同上)
int find2(int begin , int n , int m){
    int count = 0;
    while(count < m){
        if(begin == n + 1)
            begin = 1;
        if(mark2[begin] == 0){
            count++;
            if(count == m)
                break;
        }
        begin++;
    }
    return begin;
}

//处理循环过程
void output(){
    int count = 0;
    init();
    int a, b;//a b是表示两个人的位置,不是编号
    begin1 = 1 , begin2 = 1;//初始化两个人都是从他们方向的1处开始
    while(count != n){
         a = find1(begin1 , n, k);
         b = find2(begin2 , n, m);
         //cout<<"a:"<<a<<"  "<<"b:"<<b<<endl;
         //如果两个人找到同一个值
         if(p1[a] == p2[b]){
             printf("%3d" , p1[a]);
             count++;//只删除一个
         }
         if(p1[a] != p2[b]){
             printf("%3d" , p1[a]);
             printf("%3d" , p2[b]);
             count += 2;//删除两个
         }
         mark1[a] = 1;
         mark2[b] = 1;
         mark1[n-b+1] = 1; //注意第二个人走的位置,相对第一个人来说也是走过的
         mark2[n-a+1] = 1;//注意第一个人走的位置,相对第二个人来说也是走过的
         begin1 = a + 1;//指向下一个位置
         begin2 = b + 1;
         if(count != n)
             cout<<",";
    }
    cout<<endl;
}

int main(){
    int i , j;
    while(cin>>n>>k>>m){
        if(n == 0 && k == 0 && m == 0)
            return 0;
        output();
    }
    return 0;
}

//list过的,迭代器的强大应用list的好处在于它的迭代器是一个环状的
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <list>
#include <algorithm>
using namespace std;

int n , k , m , mark;
list<int>lis;//用来存储编号
list<int>::iterator it1;//it1指向第一个人的位置
list<int>::iterator it2;//it2指向第二个人的位置

//初始话函数
void init(){
    int i;
    //把编号先插入
    for(i = 1 ; i <= n ; i++)
        lis.push_back(i);
    it1 = lis.begin();//迭代器1指向开头
    it2 = --lis.end();//迭代器2指向末尾
}
//判断当前位置是否是在lis.end()
inline void judge(){
     if(it1 == lis.end())
        ++it1;//对于it1则要编程lis.begin();
     if(it2 == lis.end())
        --it2;//对于it2则要变成lis.end();
}
//第一个人的函数
int findp1(){
    int count = 1;
    while(count != k){
        it1++;
        count++;
        if(it1 == lis.end()) //如果当前位置到lis.end()就有在算一次
            count--;
    }
    return *it1;
}
//第二个人的函数
int findp2(){
    int count = 1;
    while(count != m){
        --it2;
        count++;
        if(it2 == lis.end()) //如果当前位置到lis.end()就有在算一次
            count--;
    }
    return *it2;;
}
//处理函数
void solve(){
    int i ,j , p1 , p2, count = 0;
    init();//调用初始化函数
    while(count != n){
        p1 = findp1();
        p2 = findp2();
        if(p1 == p2){
            printf("%3d" , p1);
            count++;
            if(count == n)
                break;
            it1 = lis.erase(it1);
            --it2;//对于it2只要减1即可往前
            judge();
        }
        if(p1 != p2){
            printf("%3d%3d" , p1 , p2);
            count += 2;
            if(count == n)
                break;
            it1 = lis.erase(it1);
            if(*it1 == *it2)//如果出现当前位置刚好是下个人要删除的那么it1加加
                ++it1;
            it2 = lis.erase(it2);//由于erase后指针后移,那么it2要减1
            --it2;
            judge();
        }
        if(count != n){//只要不是n输出逗号
            printf(",");
        }
    };
    cout<<endl;
}
//主函数
int main(){
    while(scanf("%d%d%d" ,&n , &k , &m)){
        lis.clear();//注意清空链表不然RE
        if(n == 0 && k == 0 && m == 0)
            break;
        solve();
    }
    return 0;
}
时间: 2024-09-20 08:40:02

Uva 133 The Dole Queue的相关文章

UVa 133 The Dole Queue:模拟循环链表

133 - The Dole Queue Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=103&page=show_problem&problem=69 In a serious attempt to downsize (reduce) the dole queue, The New National Green

UVa 133:The Dole Queue 数据结构专题

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=103&page=show_problem&problem=69 题目类型: 数据结构, 链表 题意: N份申请书,排成一个圆圈, 按逆时针方向编号为1-N. 有两个公务员,公务员1站在1,往逆时针方向数到第k份,选中:公务员2站在N,往顺时针方向数到第m份,选中. 取走选中的编号的申请书,输出编号.如果编号一

UVa 540:Team Queue 数据结构专题

题目链接: http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=103&page=show_problem&problem=481 题目类型: 数据结构, 二叉树 样例输入: 2 3 101 102 103 3 201 202 203 ENQUEUE 101 ENQUEUE 201 ENQUEUE 102 ENQUEUE 202 ENQUEUE 103 ENQUEUE 2

UVa 146 ID Codes:字典序

146 - ID Codes Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=82 It is 2084 and the year of Big Brother has finally arrived, albeit a century late. In or

UVa 540 Team Queue:STL list&amp;amp;queue模拟插队

540 - Team Queue Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=103&page=show_problem&problem=481 Queues and Priority Queues are data structures which are known to most computer scie

UVa 10128 Queue (DP)

10128 - Queue Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=115&page=show_problem&problem=1069 既然有最优子结构,不妨从DP的角度来思考. 有三个不同的维度:总人数N,从前看到的人P,从后看到的人R. 假设现在队列由i-1个人变成了i个,由于谁后进到队列是无所谓的,不

uva 540 Team Queue

点击打开链接uva 540 思路: list+map模拟 分析: 1 题目的意思是有n个队伍,每个队伍的人数为m. 2 现在有三种操作,ENQUEUE x是插入x,如果队列里面已经有x这一队的成员那么直接插入到这一队的最后一个,否则插入到队列的最后一个:DEQUEUE 是直接拿到队列的第一个元素输出,并删除队列的第一个元素:STOP是停止 3 直接利用map和list来模拟,由于题目要求要插入的具体的位置所以用list来模拟 代码: #include<map> #include<list

【UVA 10307 Killing Aliens in Borg Maze】最小生成树, kruscal, bfs

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20846 POJ 3026是同样的题,但是内存要求比较严格,并是没有过... 对以迷宫形式给定的一些点求最小生成树,不过这里的边并不是抽象的两点间笛卡尔距离,也不是折线距离(迷宫中有障碍),而是需要用四个方向的搜索来求. 用bfs求出任两点间的最短距离后,可用kruscal求出最小生成树. 这次值得一提的是对并查集的一点改造:由于每个顶点由一组(x,y)坐标唯一确定

【原创】Twemperf 中对 BSD queue.h 的兼容实现

      研究 twemperf 源码过程中,发现其中包含了针对 BSD queue.h 文件的兼容实现.并且还额外增加了  SLIST 和  STAILQ 两种结构的实现和相应操作.      下面给出的是 twemperf 中 mcp_queue.h 的源码.  ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41