• 程设刷题 | 洗纸牌问题


    目录

    纸牌

    题目描述

    分析

    方法一(极有可能超时)

    方法二(简单)

    另述


    纸牌

    题目描述

    有2N张纸牌,标号从1到2N。一次洗牌,可以将牌的排列改成n+1,1,n+2,2,...,n,2n。请问这样洗牌几次,可以让牌回到原始的状态。比如N=2时,1234->3142->4321->2413->1234 一共洗4次。

    输入

    每行输入一个整数N(1≤N≤10,000),N如果为0,表示输入结束,不需要处理。

    输出

    每行输出一个样例的结果。

    样例输入

    1
    2
    3
    4
    5
    6
    0

    样例输出

    2
    4
    3
    6
    10
    12
     


    分析

    题目给的N达到了100,000,一般的方法极有可能超时。

    下面是最先想到的成功超时的方法:

    方法一(极有可能超时)

    #include <iostream>//1210 Eddy's 洗牌问题 模拟  
    #include <string>  
    using namespace std;  
      
    int n,m;  
    void change(string &str )  
    {  
        string a;  
        for(int i=1;i<=n;i++)  
        {  
            cc++;  
            a=str[n+i];  
            str.erase(n+i,1);  
            str.insert(i*2-1,a);  
        }  
    }  
      
    int main()  
    {  
        string str,tmpstr;  
        while(cin>>n)  
        {  
            str.resize(n*2+1);  
            for(int i=1;i<=n*2;i++)  
                str[i]=i+'0';  
            m=0;  
            tmpstr=str;  
            while(1)  
            {  
                change( str );  
                m++;  
                if(tmpstr==str) break;  
            }  
            cout<<m<<endl;  
        }  
        return 0;  
    }

    后经过一番思考和演算……我发现这道题是有规律的。

    规律就是1的位置,很容易发现1的位置是从1->2->4->8……如果超过数尾则从头偏移,总之只要经过若干次移动,1再次移动在1的位置,就能够保证洗牌洗回了原序列。

    方法二(简单)

    #include<bits/stdc++.h>
    using namespace std;
    int main()
    {
        int n;
        while(scanf("%d",&n),n)
        {
            int cnt=0;
            int pos=1;
            do
            {
                if(pos<=n) pos*=2;//记录1的位置:1-2-4-8-...直到01串尾
                else pos=(pos*2-1)%(2*n);//相当于环形存储(求余操作)
                cnt++;
            }
            while(pos!=1);
            printf("%d
    ",cnt);
        }
        return 0;
    }

    另述

    当然方法不止这些!比如这种,只追踪第一张牌的位置,只有当他在第n+1的位置时下一次才会回到初始位置.你并没有考虑其他牌的位置,因为他们都是相关的,位置不会乱.

    #include <stdio.h>
    int main()
    {
        int n, x, c;
        for(; scanf("%d", &n) != EOF; printf("%d
    ", c))
        for(c = x = 1; (x = x>n ? (x-n)*2-1 : x*2) - 1; c++);
        return 0;
    }

    【附:一文一图】

  • 相关阅读:
    EditPlus使用技巧
    PL/SQL Dev的问题
    解决httpModules 未能从程序集 XX 加载类型 XXX 的错误
    IE浏览器无法显示背景,字体显示很大问题的解决办法[转]
    如何在Outlook2003中加入农历节气
    再谈Oracle在Windows下的权限问题
    Vista下安装布署注册的问题解决
    [转]关于管理的经典故事(员工激励)
    开始应用AJAX
    Aptana IDE 中文乱码的问题解决
  • 原文地址:https://www.cnblogs.com/zhouie/p/10702605.html
Copyright © 2020-2023  润新知