[问题描述]

         

一个关于翻硬币的问题,
一摞硬币共有m枚,每一枚都是正面朝上。取下最上面的一枚硬币,将它翻面后放回原处。然后取下最上面的2枚硬币,将他们一起翻面后再放回原处。再取3枚,取4枚……直至m枚。然后再从这摞硬币最上面的一枚开始,重复刚才的做法。这样一直做下去,直到这摞硬币中的每一枚又都是正面朝上为止。例如,m为1时,翻两次即可。m为2时,翻3次即可;m为3时,翻9次即可;m为4时,翻11次即可;m为5时,翻24次即可;…;m为30时,翻899次即可;…
输 入:
  仅有的一个数字是这摞硬币的枚数m,0<m<1000。
  输 出:
  为了使这摞硬币中的每一枚又都是正面朝上所必需翻的次数。
  某单元格输入:
      30
  某单元格等于:
      899
 
下面是我自己的两种解法
[解法一]
思路:每一轮的翻转后,能得到每一枚硬币当前的位置的位置,如果硬币重新回到原先的位置(基数个硬币时)或者相反的位置(偶数个硬币时),就的到了求解。
         //查找每轮循环后的位置
        int GetTurnAfterPos(int n, int turn, int m)
        {
               int TurnNum ;//每轮翻转次数
               int TurnAfterPos; //每轮循环后的位置
              TurnNum = turn - n + 1;
              if(TurnNum % 2 == 0) //为偶数次循环
                     TurnAfterPos = n + TurnNum / 2;
              else                //为奇数次循环
                     TurnAfterPos = (TurnNum + 1) / 2;
              return TurnAfterPos;
        }
        //每一轮翻转之后的位置:
        int solve(int turn, int * CurrentPos, int m)
        {
             if(turn == 0)
                    return 0;
             for(int i = 0; i < turn; i ++)
             {
                    int RetNum = GetTurnAfterPos(i+1, turn, m);
                    CurrentPos[RetNum-1] = CurrentPos[m+i];
             }
             for(i = 0; i < m; i ++)
            {
                   CurrentPos[i+m] = CurrentPos[i];
             }
             return 0;
       }
         int main()
       {
              int m = 30;//硬币总数 
              int * CurrentPos = new int[m*2]; 
              int n = 0;//翻转次数
              bool flag = false;
              do
             {  
                   n++;
                   for(int i = 0; i < m*2; i++)
                           CurrentPos[i] = i % m + 1;
                  int x = n / m;
                  int y = n % m;
                  for(i = 0; i < x; i++)
                          solve(m, CurrentPos, m);
  
                  solve(y, CurrentPos, m);
                  for(i = 0; i < m; i ++)
                  {
                           printf("%d ",CurrentPos[i]); 
                  }
                  //solve(5, CurrentPos, m);
                  printf("/n");
                  for(i = 0; i < m; i++)
                 {
                           if(CurrentPos[i] != i+1)
                           {
                                 break;
                           }  
                           if(i == m - 1 && n > 1)
                                 flag = true;
                }  
          }
          while(!flag);
               if(m % 2 == 0)
                      printf("翻转的总次数是:    %d/n", n - 1); 
              else
                     printf("翻转的总次数是:    %d/n", n); 
              delete []CurrentPos;
              return 0;
     }
[解法二]
思路:不管硬币的次序,只是记住每次的翻转和交换,硬币的初始状态都是TRUE,每个COIN经过多伦的翻转后都变回TRUE,那么就求出了解,这是最简单的思路。
      void solve(int m)
    {
          bool * CurrentSurface = new bool[m];
          for(int i = 0; i < m; i++)
          CurrentSurface[i] = true;
         int turnTimes = 0;//翻转次数
         bool bSuccess = false;
         do
         {
              for(int i = 0; i < m; i++)
              {
                     for(int j = 0; j < (i+1) / 2; j ++)
                    {
                             //turnCoin(j, i - j + 1);
                             bool temp = CurrentSurface[j];
                             CurrentSurface[j] = !CurrentSurface[i - j];
                             CurrentSurface[i - j] = !temp;
                    }
                    if((i+1) % 2 == 1)
                             CurrentSurface[i/2] = !CurrentSurface[i/2];  
                   turnTimes=turnTimes+1;
                   bSuccess = true;
                   for(int n = 0; n < m; n ++)
                   {
                        if (CurrentSurface[n] == false)
                        {
                             bSuccess = false;
                             break;
                        }
                   }
                   if(bSuccess)
                        break;
              }
         }while(!bSuccess);
         printf("翻转的总次数是:    %d/n", turnTimes);
         delete [] CurrentSurface;
}
 
int main()
{
     int CoinCount = 1;
     while(CoinCount > 0)
     {
          printf("请输入硬币的总数:");
          scanf("%d",&CoinCount);
          solve(CoinCount);
     }      
      return 0;
}
 
网上还有几种解法,也同时列了出来:
[解法三]
这个是最难理解的一个算法,因为没有注释,呵呵。
int solve(int  m); 
int main() 
{  
     int  m;  
     do  {  
              scanf("%d",  &m);  
              if(m  >  0  &&  m  <  1000)  
              printf("%d/n/n",  solve(m));  
     }  while(m  >  0  &&  m  <  1000); 

int  solve(int  m) 
{  
     int  I,  
     t, 
     d, 
     s = -  1; //翻转的次数 
    int  flag;
    //如果只有一枚硬币,翻两次就能达到目标
    if(m == 1) 
         s = 2; 
    else
   { 
         d = 2  *  m  +  1;    //确定硬币是经过偶数次翻转还是奇数次翻转
         t = 2;        //表示一个COIN必须翻转偶数次,才能从正面继续翻回到正面。 
         I = 1;        //翻转的轮数,每轮为从1翻转到m
         flag = 0;    //退出循环标志,翻转完成标志
  
         printf("d  =  %d:/n",  d);  
         do { 
              printf("/tt(%d)  =  %d,  /t  s:  %3d,  %3d/n",  I,  t,  I  *  m,  I  *  m  -  1); 
              if(t == 1)            //
              {  
                       s = I * m; 
                       flag = 1; 
              } 
              else if(t == 2 * m)      { 
                      s = I * m - 1; 
                      flag = 1; 
             } 
             else                      
             {
                     t = (t  *  2)  %  d; 
             }
             I = I + 1; 
       }  while(!flag); 
   } 
   printf("s  =  %d,  I  =  %d,  t  =  %d,  d  =  %d/n",  s,  I,  t,  d); 
   return  s; 
}
 
[解法四]
思路: 设 题设的从1到n的翻转为一轮番转,位置   pos,   turnNum   为位置pos所需要的翻转次数 ,假设有5个硬币,我们按其位置分别编号   1,2,3,4,5 经过一轮翻转后,变成了5,3,1,2,4;可以看到原来1位置的硬币现在到了3。这一点说明一轮翻转过后,pos的排列是有规律的,另外,任意位置上的元素的翻转次数为turnNum   =     num+1-pos;   
由以上分析得到了,任意位置pos,经过一轮番转后的位置变为了new_pos   =   num/2   +   1   +   turnNum/2   -   turnNum%2*turnNum   所以,可以由上式计算出new_pos。那么,如果new_pos也为1的话,则所有的硬币都回到了原来的位置,且都朝正面。   
  #include   "stdio.h"  
  int   solve(int   m)  
  {  
          int   I   =   0;  
          int   pos,turnNum,temp,s;  
          turnNum   =   0;  
          if(m   ==   1)   s   =   2;  
          else  
          {  
                  pos   =   1;  
                  I   =   0;  
                  do  
                  {  
                          I++;  
                          temp   =   m+1-pos;  
                          turnNum   +=   temp;  
                          pos   =   m/2   +   1   +   pos/2   -   temp%2*(pos/2)*2;  
                  }while(pos!=1);  
                  s   =   I*m   -   turnNum%2;         //the   sum   of   times  
          }  
          return   s;  
  }  
   
  main()  
  {  
          int   m;  
          do  
          {       scanf("%d",&m);  
                  printf("the   sum   is   :   %d/n",solve(m));  
          }while(m   !=   -1);  
  }   
  
[解法五]
      思路: 直接模拟
      #include<iostream>  
      #include<stdlib.h>  
      #define   swap(a,b){int   t=!a;   a=!b;   b   =   t;}   
      int     n;  
      int   flag[1000];  
       
       
      bool   isright()  
      {            
                for(int   i=0;   i<n;   i++)    
                        if(!flag[i])  
                            return   false;  
                return   true;              
      }    
     
      int   turncoin()  
      {          
              int   total   =   1;  
                       
              while(1)  
              {  
                    int   k   =   total%n;  
                    int   i,j;  
                    for(   i=0,j=k;   i<=j;   i++,   j--)  
                          swap(flag[i],flag[j]);  
                    total++;                  
                    if(isright())  
                          return   total;        
              }  
              return   total;  
      }  
       
      void   init()  
      {          
     
                  for(int   i=0;   i<n;   i++)    
                        flag[i]   =   1;    
                flag[0]   =   0;  
     
      }  
      int   main()  
      {  
               
    while(std::cin >> n && n>0)  
              {          
                    init();    
     std::cout << turncoin() << std::endl;              
              }  
              return   0;  
                             
      }    

翻硬币问题的多种求解相关推荐

  1. 蓝桥杯历届试题----矩阵翻硬币

    矩阵翻硬币 问题描述 小明先把硬币摆成了一个 n 行 m 列的矩阵.随后,小明对每一个硬币分别进行一次 Q 操作.对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进 ...

  2. 浅谈 翻硬币游戏【Nim博弈】

    ACM博客_kuangbin 博弈-翻硬币游戏 hihoCoder 1172 : 博弈游戏·Nim游戏·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Alice和B ...

  3. 试题 历届试题 翻硬币(贪心)

    试题 历届试题 翻硬币 资源限制 时间限制:1.0s 内存限制:256.0MB Work hard,Play harder. 问题描述 小明正在玩一个"翻硬币"的游戏. 桌上放着排 ...

  4. 蓝桥杯 - 翻硬币(贪心)

    小明正在玩一个"翻硬币"的游戏. 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面(是小写字母,不是零). 比如,可能情形是:**oo***oooo        ...

  5. 【DP】翻硬币(jzoj 3921)

    翻硬币 jzoj 3921 题目大意: 给你一个长度为nnn的当前01串和目标01串,现在你要做mmm此操作,每次操作你要使kkk个不同的位取反,现在问你有多少种方法可以使当前01串变为目标01串 输 ...

  6. 牛客14355 翻硬币

    链接:https://ac.nowcoder.com/acm/problem/14355 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536 ...

  7. 蓝桥杯练习系统历届试题 翻硬币

    问题描述 小明正在玩一个"翻硬币"的游戏. 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面(是小写字母,不是零). 比如,可能情形是:**oo***oooo 如 ...

  8. 蓝桥杯试题:矩阵翻硬币

    矩阵翻硬币 这是蓝桥杯的一道练习题,题目如下: 问题描述 小明先把硬币摆成了一个 n 行 m 列的矩阵. 随后,小明对每一个硬币分别进行一次 Q 操作. 对第x行第y列的硬币进行 Q 操作的定义:将所 ...

  9. HDU-3537 Mock Turtles型翻硬币游戏

    题意:<=10^8不定个硬币,给你n<=100个正面朝上的硬币以及他们所在的位置,可任选1/2/3个硬币反转(不必连续),但要求翻的这1/2/3个硬币中的最右侧的一个是正面朝上的,问先手者 ...

最新文章

  1. Oracle数据库物理存储结构管理
  2. 关于Hinton团队无监督新作SimCLR的所思所想
  3. python3 模块编写_python3 _pickle模块详解
  4. (仿头条APP项目)1.app载入界面相关功能实现
  5. OpenCV学习笔记(五):Mat结构
  6. JSON-lib 使用
  7. Jerry Wang重装系统的一些备份
  8. python菜鸟教程split_Python split()方法
  9. java集合转换_java各种集合的转换
  10. oracle数据库相关知识,Oracle数据库相关知识点复习
  11. 便携本市场一片混乱 东芝也加入战斗
  12. 小程序坑集【日常总结,持续更新(11.08更新)】
  13. 两道关于回溯法,分支限界法的算法题
  14. ie java 注册表,win7在桌面显示IE图标的注册表
  15. 解析《啊哈C》--最终章:用C语言制作走迷宫和推箱子的小游戏
  16. python_大智慧SAR指标编写
  17. android webview静态方法,在android webview中加载静态页面
  18. Heli Track
  19. sessionbean+entitybean 在 jbx+wl7中调试笔记。
  20. CAD学习笔记中级课【导入导出】

热门文章

  1. 为自己写下一份人生清单
  2. excel2013将表格打印在一张纸上
  3. 职称外语 计算机应用能力要求,关于职称外语和计算机应用能力要求有关问题的解释说明...
  4. 什么是 CAPTCHA
  5. 《Essential C++》笔记
  6. 上善若水——项目管理的真谛
  7. JavaScript特点
  8. 『最新』关于联想IdeaPad Y430A-TSI一周有感!!
  9. 音频比特率_将音频文件转换为更高的比特率有意义吗?
  10. 转 -- Oracle Interested Transaction List (ITL) Waits