当前位置:编程学习 > C/C++ >>

C++学习 POJ3032 CARD TRICK

题意:我们要利用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,比较方便。
 
代码(0ms AC):
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n,t,ans[20];
void solve(){
    deque Q;
    for(int i=1;i<=n;i++)
      Q.push_back(i);
    int s=1;
    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++;
       Q.pop_front();
    }
    for(int i=1;i<=n;i++)
     if(i!=n)
      printf("%d ",ans[i]);
     else printf("%d\n",ans[i]);
}
int main()
{
    scanf("%d",&t);
    while(t>=1){
       scanf("%d",&n);
       solve();
    }
    //system("pause");
    return 0;
补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,