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++ ,