E -- POJ 3032 Card Trick

Card Trick

Time Limit: 1000 MS Memory Limit: 65536 KB

64-bit integer IO format: %I64d , %I64u Java class name: Main

[Submit] [Status] [Discuss]

Description

The magician shuffles a small pack of cards, holds it face down and performs the following procedure:

  1. The top card is moved to the bottom of the pack. The new top card is dealt face up onto the table. It is the Ace of Spades.
  2. Two cards are moved one at a time from the top to the bottom. The next card is dealt face up onto the table. It is the Two of Spades.
  3. Three cards are moved one at a time…
  4. This goes on until the nth and last card turns out to be the n of Spades.

This impressive trick works if the magician knows how to arrange the cards beforehand (and knows how to give a false shuffle). Your program has to determine the initial order of the cards for a given number of cards, 1 ≤ n ≤ 13.

Input

On the first line of the input is a single positive integer, telling the number of test cases to follow. Each case consists of one line containing the integer n.

Output

For each test case, output a line with the correct permutation of the values 1 to n, space separated. The first number showing the top card of the pack, etc…

Sample Input

2
4
5

Sample Output

2 1 4 3
3 1 4 5 2

Source

Nordic 2006
 
 

题目大意:

我们要利用n张牌表演一个魔术,魔术的步骤是这样的:

将开头一张牌移动到最后,接着拿出这堆牌的第一张,这张牌的数字是1,将这张牌丢弃

将开头二张牌移动到最后,接着拿出这堆牌的第一张,这张牌的数字是2,将这张牌丢弃

将开头三张牌移动到最后,接着拿出这堆牌的第一张,这张牌的数字是3,将这张牌丢弃

……

将开头n张牌移动到最后,接着拿出这堆牌的第一张,这张牌的数字是n

问你,假如要成功地表演这个魔术,我们要将这n张牌排成什么样子?请输出这个排列。

 

解题分析:

一道简单的模拟题。一开始就有一个直观想法,枚举14个数字的全排列,然后依次模拟,判断哪一个解是符合魔术步骤的,输出它。但是我算了一下,14个数字的全排列是:87178291200,很明显,枚举必定超时。这题其实是要用逆向思维,首先我们必须明确一点,那就是:第一张牌一定在牌堆的第二个位置。其实这就是此题的突破口:每张牌的所在位置都是根据上一个状态推出的。让我来举个例子,对于样例n=4,模拟的过程就是:

设第一张牌的数字是x1,第二张牌为x2,第三张牌为x3,第四张牌为x4

当前牌堆序列为:x1  x2  x3  x4

将第一张牌移到最后,原序列为: x2 x3 x4 x1,也就是说x2一定是1

删除x2,继续模拟,将前两张牌移动到最后,原序列为:x1 x3 x4,也就是说x1一定是2

以此类推,我们可以还原出整个序列:2 1 4 3。

我使用了deque(双端队列)来模拟整个过程,因为双端队列支持pop_front和push_front,比较方便。

 

代码:

#include <iostream>
#include <cstdio>
#include <deque>
using namespace std;

int n,t,ans[20];    // ans数组中下标即扑克牌初始位置x1,x2...xn,其值即为扑克牌的值
void solve(){
    deque<int> Q;   //定义一个双向队列,在函数内部定义省时16ms
    for(int i=1;i<=n;i++)
      Q.push_back(i);
    int s=1;        // s 即是输出扑克牌的值:1,2...n
    while(!Q.empty()){  //模拟魔术过程
       for(int i=1;i<=s;i++){
           int x=Q.front();
           Q.pop_front();
           Q.push_back(x);
       }
       ans[Q.front()]=s++;  //ans[xi]对应的值s即为扑克牌的值
       Q.pop_front();
    }
    for(int i=1;i<=n;i++)   //将ans数组输出
     if(i!=n)
      printf("%d ",ans[i]);
     else printf("%d\n",ans[i]);
}
int main()
{
    scanf("%d",&t);
    while(t--){
       scanf("%d",&n);
       solve();
    }
    return 0;
}

 

 补充知识:

双向队列:

头文件:#include <deque>

声明: deque<int> q;

pop_back()删除尾部的元素

pop_front()删除头部的元素

push_back()在尾部加入一个元素

push_front()在头部加入一个元素

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值