Hdu - 1210 - Eddy's 洗牌问题

  因为考试所以最近都没有做什么题。想不到这题都卡(~~~~(>_<)~~~~ ),看来太久没有做题感觉变迟钝了,当然也有原因是找规律的题做得比较少,所以就这样了,看来要快快调整好,好好努力才行。

先上题目

Eddy's 洗牌问题

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2602    Accepted Submission(s): 1718


Problem Description
Eddy 是个ACMer,他不仅喜欢做ACM题,而且对于纸牌也有一定的研究,他在无聊时研究发现,如果他有2N张牌,编号为 1,2,3..n,n+1,..2n。这也是最初的牌的顺序。通过一次洗牌可以把牌的序列变为 n+1,1,n+2,2,n+3,3,n+4,4..2n,n。那么可以证明,对于任意自然数N,都可以在经过M次洗牌后第一次重新得到初始的顺序。编程 对于小于100000的自然数N,求出M的值。
 

 

Input
每行一个整数N
 

 

Output
输出与之对应的M
 

 

Sample Input
20 1
 

 

Sample Output
20 2
 
 
 
  数据范围一看就知道不可以直接模拟,于是先先写了一个直接模拟的看看规律,结果没有看出什么端倪出来。只发现1的位置一开始是1->2->4···这样变化,后来还是不得不上网看了一下题解,发现只需要判断1有没有回到一开始的位置就可以了,1的变化就是一开始是1->2->4```这样变化,但是当去到后面到达不了2的n次幂的情况下,就要按照题目的方法把1放回到前面,位置在(i-n)*2-1,其中i是1的当前位置,n是输入的n,i要大于n且i*2也要大于2*n才执行这一步。
 
上代码
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #define MAX 10000
 5 
 6 using namespace std;
 7 /*
 8 typedef struct
 9 {
10     int d[MAX];
11 }D;
12 
13 D s;
14 
15 void loadlist(D u,int m)
16 {
17     int i;
18     for(i=1;i<=m;i++) printf("%d ",u.d[i]);
19     printf("\n");
20 }
21 
22 bool check(D u,int m)
23 {
24     int i;
25     for(i=1;i<=m;i++) if(u.d[i]!=s.d[i]) return 0;
26     return 1;
27 }
28 
29 void deal(int n)
30 {
31     int i,j,m,count;
32     D u,v;
33     m=n*2;
34     count=0;
35     u=s;
36     loadlist(u,m);
37     while(!count || !check(u,m))
38     {
39         for(j=2,i=1;j<=m;j+=2,i++) v.d[j]=u.d[i];
40         for(j=1;j<=m;j+=2,i++) v.d[j]=u.d[i];
41         u=v;
42         count++;
43         loadlist(u,m);
44     }
45     printf("%4d %4d %4d\n",n,m,count);
46 }
47 
48 int main()
49 {
50     int n,i;
51     char o;
52     n=0;
53     freopen("data.txt","w",stdout);
54     while(n<=100)
55     {
56         //(o=getchar())!=EOF
57         n++;
58         for(i=1;i<=2*n;i++) s.d[i]=i;
59         deal(n);
60     }
61     return 0;
62 }
63 */
64 
65 int main()
66 {
67     int i,n,m,count;
68     while(scanf("%d",&n)!=EOF)
69     {
70         i=1;
71         m=2*n;
72         count=0;
73         while(!count || i!=1)
74         {
75             if(i*2>m && i>n)
76             {
77                 i-=n;
78                 i=i*2-1;
79             }
80             else i*=2;
81             count++;
82         }
83         printf("%d\n",count);
84     }
85     return 0;
86 }

 

  其中前面的代码用来直接模拟得到每一步的序列,同时有最后的移动步数。真正需要提交的代码只有一小段。

    
posted @ 2013-07-03 15:42  海拉鲁的林克  阅读(232)  评论(0编辑  收藏  举报