zoukankan      html  css  js  c++  java
  • 5-28 猴子选大王

    一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?

    输入格式:

    输入在一行中给一个正整数 N(≤ 1000)。

    输出格式:

    在一行中输出当选猴王的编号。

    输入样例:

    11
    

    输出样例:

    7
    

    解题思路:

    • 第一种方法(算法一):
      给每个猴子初始设为 0,退出时就置为 1,最后检查数组中的数字,是 0 就输出。难点在于让判断循环进行以及循环出口。
      • 让判断循环进行:当 i == N 时,将其置 0,这样就能继续循环。
      • 循环出口:直到退出的猴子数等于 N-1,就是还剩一只猴子就退出。
    • 第二种方法(算法二):
      增加一个数组,每次将数组筛选,将剩下的猴子放进新的数组里。直到数组里就剩 2 只猴子(与筛选算法有关)。在文章的最后会解释算法二中的一点小细节。

    另外,要注意数组的初始化
    scanf("%d", N);
    int a[N]={0};
    初始化的时候 N 的值需要已知。初始化是在编译时完成。所以 N 尚未输入。这样就会产生错误。解决方法是用一个 for 循环完成初始化。

    解题代码:

    算法一
    #include<stdio.h> 
    
    int main ()
    {
    	int N, i;
    	scanf("%d", &N);
        int a[N+1]; //舍弃 a[0],方便给猴子编号 
        for (i=1; i<N+1; i++) { //初始化数组 
    		a[i] = 0; 
        }
    	
    	int count = 0, quit = 0;
    	if (N != 1) {
    		for (i=1; i<N+1; i++) {
    			if (a[i] == 0) count ++;
    			if (count % 3 == 0 && a[i] == 0) {
    				a[i] = 1; // 退出的猴子标记为 1
    				quit ++;
    				if ( quit == N-1) break;
    			}
    			if (i == N) i = 0; //让其循环 
    		}
    	}
    
        for (i=1; i<N+1; i++) { 
        	if (a[i] == 0) {
        		printf("%d
    ", i);
        		break;
        	}
        }
    
    	return 0; 
    }
    
    算法二
    #include<stdio.h>
    
    int main ()
    {
    	int N, i;
    	scanf("%d", &N);
        int a[N+1]; // 舍弃 a[0],方便给猴子编号 
        for (i=1; i<N+1; i++) { //初始化数组 
    		a[i] = i; 
        }  
    	
    	int count;
    	int b[N+1]; // 舍弃 b[0],方便给猴子编号 
    	while (N > 2) {
    		for (i=1; i<=N; i++) {
    			if (i == 1) {
    				switch (N % 3) {
    					case 0: count = 1; break;
    					case 1: count = 2; break;
    					case 2: count = 3; break;
    				} // 算法的下方会给出讲解
    			}
    			if (i%3 != 0 && i<=N/3*3) {
    				b[count++] = a[i];
    			} 
    			if (i%3 != 0 && i>N/3*3) {
    				switch (N % 3) {
    					case 0: break;
    					case 1: b[1] = a[i]; break;
    					case 2: 
    						if (i == N) {
    								b[1] = a[i-1]; 
    								b[2] = a[i];
    						}
    							break;
    				}						
    			}
    		}
    		N = count - 1;
    		for (i=1; i<=count-1; i++) {
    			a[i] = b[i];
    		} // 将新的数组 b 赋给原数组 a
    	}
    	
    	if (N == 1) {
        	printf("1
    ");
    	} else {
    		printf("%d
    ", a[2]);
    	}
    	
    	return 0; 
    }
    
    算法二中的一点细节:
    if (i == 1) {
    	switch (N % 3) {
    		case 0: count = 1; break;
    		case 1: count = 2; break;
    		case 2: count = 3; break;
    	} // 算法的下方会给出讲解
    }
    

    在形成新的数组之后,要从第一个开始访问,当 N 不同的时候,第一个的情况会有所不同,所以有了上面的处理。

    • 比如 N = 3 时,

      a[i] 1 2 3
      猴子编号 1 2 3

      b[count] 1 2
      猴子编号 1 2

      当 N 恰为 3 的倍数时,下一次从猴子 1 号开始数。所以 switch 那里将 b 的初始指针设为了 1。

    • 而当 N = 4 时,

      a[i] 1 2 3 4
      猴子编号 1 2 3 4

      b[count] 1 2 3
      猴子编号 4 1 2

      当 N 为 4 的时候,下一次从猴子 4 号开始数,所以 switch 那里将 b 的初始指针设为了 2。把 b[1] 的位置留给 4 号猴子。

    • 而当 N = 5 时,

      a[i] 1 2 3 4 5
      猴子编号 1 2 3 4 5

      b[count] 1 2 3 4
      猴子编号 4 5 1 2

      当 N 为 5 的时候,下一次从猴子 4 号开始数,所以 switch 那里将 b 的初始指针设为了 3。把 b[1] 的位置留给 4 号猴子,b[2] 的位置留给 5 号猴子。

  • 相关阅读:
    C#Redis分布式缓存
    CPU核心数
    关于RSA加密
    C#.NET中的CTS、CLS和CLR
    silverlight依赖属性
    silverlight imagesource赋值与转换
    #我的java之多态和接口#
    #什么是 spring boot#
    #替换eclipse自带的maven#
    #从零开始的maven异世界#
  • 原文地址:https://www.cnblogs.com/andywenzhi/p/5738353.html
Copyright © 2011-2022 走看看