天天看點

隊列水題

隊列水題

(另附約瑟夫環士兵隊列訓練問題 來源: ​​https://cn.vjudge.net/contest/268984#problem/B​​ 某部隊進行新兵隊列訓練,将新兵從一開始按順序依次編号,并排成一行橫隊,訓練的規則如下:從頭開始一至二報數,凡報到二的出列,剩下的向小序号方向靠攏,再從頭開始進行一至三報數,凡報到三的出列,剩下的向小序号方向靠攏,繼續從頭開始進行一至二報數。。。,以後從頭開始輪流進行一至二報數、一至三報數直到剩下的人數不超過三人為止。

Input:

本題有多個測試資料組,第一行為組數N,接着為N行新兵人數,新兵人數不超過5000。

Output:

共有N行,分别對應輸入的新兵人數,每行輸出剩下的新兵最初的編号,編号之間有一個空格。

//queue模拟
#include<cstdio>
#include<queue>
using namespace std;
int main()
{
  int t,n;
  scanf("%d",&t);
  while(t--)
  {
    queue<int>q;//隊列定義,放在裡面是為了每次清空隊列
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
      q.push(i);//把每個人的編号都按順序壓入隊列中
    }
    int p=1,x,k;
    while(q.size()>3)//如果還有超過三個人,繼續進行編号和排除等操作
    {
      x=q.size();//目前一共有多少人
      if(p&1)//如果是第奇數次,那麼就是從 1 到 2 編号 
      {
        for(int i=0;i<x/2;++i)//循環操作
        {
          k=q.front();//<span style="font-family: Arial, Helvetica, sans-serif;">取出編号為 1 的</span>
          q.push(k);//把編号為 1 的放後邊,入隊
          q.pop();//抛棄編号為 1 (已經放後面了,這個就不需要了)
          q.pop();//現在彈出的編号為 2 ,抛棄...
        }
        if(x&1)
        {
          k=q.front();//如果剛開始的時候為奇數個,那麼最後還有一個人沒被循環過....
          q.push(k);//放隊尾
          q.pop();//抛棄.....
        }
      }
      else//第偶數次,那就是從 1 到 3 編号
      {
        for(int i=0;i<x/3;++i)
        {
          k=q.front();q.push(k);//處理編号為 1 ,處理方式和前面一樣.....
          q.pop();
          k=q.front();q.push(k);//處理編号為 2 
          q.pop();
          q.pop();//抛棄編号為 3 的
        }
        while(x%3!=0)//這裡和前面的道理一樣,防止有人未處理完
        {
          --x;
          k=q.front();q.push(k);//處理剩餘的那幾個....
          q.pop();
        } 
      }
      ++p;
    }
    while(q.size()!=1)//輸出,這樣是為了控制格式...
    {
      printf("%d ",q.front());
      q.pop();
    }
    printf("%d\n",q.front()); 
  }
  return 0;
}      
//數組模拟1
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int a[5005],b[5005];
int main()
{
    int T,n,m,i,j,k,t,d[5];
    scanf("%d",&T);
    while(T--)
    {
    scanf("%d",&n);
    //n=T;
    for(i=1;i<=n;i++)//這裡面的數組a用來存放士兵在隊列中的編号(新組成的會有新的編号) 
    {
        a[i]=i; 
        b[i]=1;//數組b用來如果在隊列中,則用1來表示,如果出列,則用0來表示 
    }
    t=n;//因為這裡面的n會在計算中發生變化,是以要重新指派,用另一個變量代替它發生變換! 
    if(n>3)//當n>3的時候,因為需要出列,是以按照題意執行就可以了,記住,執行過之後 
    for(j=1;j<=n;j++)//士兵的順序不發生改變,但是序号發生了變化!,是以在他們每出列一次要重新 
    {
    for(i=1,k=0;i<=n;i++)//給士兵進行指派操作!但是最後需要輸出原來的編号! 
    {
        if(a[i]%2==0&&b[i])//這并不難,因為标記數組的下标你又沒有發生改變,是以到時候 
        {
            b[i]=0;//将數組b中對應是1的元素的下标輸出來就行了! 
            t--;
        }
        else if(b[i])
        {
            k++;
            a[i]=k;
        }
       }
        if(t<=3)
          break;
    for(i=1,k=0;i<=n;i++)
    {
        if(a[i]%3==0&&b[i])
        {
            b[i]=0;
            t--;
        }
        else if(b[i])
        {
            k++;
            a[i]=k;
        }
    }
        if(t<=3)
            break;
    }
       for(i=1,j=0;i<=n;i++)//因為題上格式要求比較嚴格,是以要進行指派到一個數組中,進行 
       {
            if(b[i])//比較規格的輸出! 
               d[j++]=i;    
       }
       if(t==3)
          printf("%d %d %d\n",d[0],d[1],d[2]);
       else if(t==2)
        printf("%d %d\n",d[0],d[1]);
       else if(t==1)
         printf("%d\n",d[0]);
    }
    return 0;
}      
//數組模拟2
#include<iostream>
using namespace std;
int f[5005];
int main()
{
  int t;
  int n,i;
  
  while(cin>>t)
  {
    while(t--)
    {
      cin>>n;
      for(i=1;i<=n;i++)
        f[i]=i;
      int t;
      if(n<=3)
      {
        printf("1");
        for(i=2;i<=n;i++)
          printf(" %d",i);
        printf("\n");
        continue;
      }
      while(1)
      {
        int leap=0;
        for(i=1;i<=n;i++)
        {
          if(f[i]!=-1)
          {
            leap++;
          }
          if(leap==2)
          {
            leap=0;
            f[i]=-1;
          }
        }
        t=0;
        for(i=1;i<=n;i++)
          if(f[i]!=-1)
            t++;
          
          if(t<=3)
            break;
          
          leap=0;
          for(i=1;i<=n;i++)
          {
            if(f[i]!=-1)
              leap++;
            if(leap==3)
            {
              f[i]=-1;
              leap=0;
            }
          }
          t=0;
          for(i=1;i<=n;i++)
            if(f[i]!=-1)
              t++;
            if(t<=3)
              break;
            
      }
      for(i=1;i<=n;i++)
        if(f[i]!=-1)
        {
          printf("%d",f[i]);
          break;
        }
        i++;
        for(;i<=n;i++)
          if(f[i]!=-1)
            printf(" %d",f[i]);
          printf("\n");
    }
  }
  
  return 0;
}