/**/ /*洗牌问题 设2n张牌分别标记为1, 2, ..., n, n+1, ..., 2n,初始时这2n张牌按其标号从小到大排列。经一次洗牌后,原来的排列顺序变成n+1, 1, n+2, 2, ..., 2n, n。即前n张牌被放到偶数位置2, 4, ..., 2n,而后n张牌被放到奇数位置1, 3, ..., 2n-1。可以证明对于任何一个自然数n,经过若干次洗牌后可恢复初始状态。现在你的的任务是计算对于给定的n的值(n≤10^5),最少需要经过多少次洗牌可恢复到初始状态。 输入输出格式 输入数据由多组数据组成。每组数据仅有一个整数,表示n的值。 对于每组数据,输出仅一行包含一个整数,即最少洗牌次数。 样例输入 10 样例输出 6*/ NO. 1 直接用一个一维数组模拟,速度超慢,代码如下:#include < stdio.h > #define MAX 20002 int main( void ) ... { int a[MAX]=...{0},n2; int i,j,k,n,t,total=0; scanf("%d",&n) ; n2 =n*2 ; for(i=1 ; i<= n2 ; i++) a[i] = i ; while (1) ...{ for(i=n+1,k=1; i<= n2 ; i++,k+=2) ...{ t = a[i] ; for(j=i-1 ; j>= k ; j--) a[j+1] = a[j] ; a[k] = t ; /**//*for(j=1 ; j<= n2 ; j++) printf("%d ",a[j]); printf(" ");*/ } total ++ ; if ( a[1] == 1) break ; } printf(" total = %d ",total); system("pause"); return 0 ;} NO. 2 用两个一维数组模拟,速度大大提高:代码如下:#include < stdio.h > #include < time.h > #define MAX 20002 int main( void ) ... { clock_t end,begin ; int a[MAX]=...{0},b[MAX],n2; int i,j,k,n,t,total=0; scanf("%d",&n) ; begin = clock(); n2 =n*2 ; for(i=1 ; i<= n ; i++) a[i] = i ; for(j=n+1,i=1; j<= n2 ; j++,i++) b[i] = j ; while (1) ...{ for(i=n,j=n; i>= 1; i--,j--) ...{ t= i+i ; a[t] = a[i] ; a[t-1]=b[j] ; } for(i=n+1,j=1; i<= n2 ; j++,i++) b[j] = a[i] ; total ++ ; if ( a[1] == 1) break ; } printf("total = %d ",total); end = clock(); printf("%d has cost %lf seconds!!! ",n,(double)(end-begin)/CLOCKS_PER_SEC); system("pause"); return 0 ;} NO. 3 找规律,然后简化过程,你会发现:其它只要1还原了,那么其它的也会还原,因此只要找到1还原时停止就OK了 /**/ /*这题目,比较经典,找规律的,只要找到a[1] = 1 时停止就OK了。。。。简写程序如下:*/ #include < stdio.h > int main( void ) ... { int total=1,a1=2; /**//*找到了第一个位置第一次出现1时就停止,此时即洗牌完成*/ int n,k; scanf("%d",&n) ; k = n<<1 ; while ( a1 != 1) ...{ if(a1 <= n) a1 <<= 1 ; else a1 = (a1<<1)-k-1 ; total ++; } printf("%d ",total) ; return 0;}