zoukankan      html  css  js  c++  java
  • 分治算法——在真币中找出伪币

    装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。我们要找出这个伪造的硬币。我们有一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同.

    第一种方法:比较硬币1与硬币2的重量。假如硬币1比硬币2轻,则硬币1是伪造的;假如硬币2比硬币1轻,则硬币2是伪造的。这样就完成了任务。假如两硬币重量相等,则比较硬币3和硬币4。同样,假如有一个硬币轻一些,则寻找伪币的任务完成。假如两硬币重量相等,则继续比较硬币5和硬币6。按照这种方式,可以最多通过8次比较来判断伪币的存在并找出这一伪币。

    第二种方法:(利用分治算法

    首先,随机选择8个硬币作为为A组,剩下的8个硬币作为B组。这样,就把1 6个硬币的问题分成两个8硬币的问题来解决。其次,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。最后,在第三步中,用第二步的结果得出原先1 6个硬币问题的答案。若仅仅判断硬币是否存在,则第三步非常简单。无论A组还是B组中有伪币,都可以推断这1 6个硬币中存在伪币。因此,仅仅通过一次重量的比较,就可以判断伪币是否存在。
    利用分治策略来解决该问题的话,
    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define ARRAY_SIZE 16
    #define TRUE       1
    #define FALSE      0
    
    int CallTimes = 0;
    
    // 生成包含 'N' 个硬币重量的数组( 含 1 枚伪币 ), 并返回伪币位置 ...
    int CreateRandomCoinWeightArray( int *p, int N )
    {
      int i, kt;
      int TrueCoinWeight, FakeCoinWeight;
      int IsStop;
    
      // 生成随机数种子 ...
      srand( ( unsigned )time( NULL ) );
    
      // 生成随机真币重量值( 在 50 至 100 之间 ) ...
      TrueCoinWeight = 50 + rand( ) % ( 100 - 50 );
    
      // 生成随机伪币位置( 在 0 ~ N-1 之间 ) ...
      kt = rand( ) % N;
    
      // 设置真币重量 ...
      for( i = 0; i < N; i++ )
        if ( i != kt )
          *( p + i ) = TrueCoinWeight;
    
      // 生成 1 个比真币略轻的伪币重量值 ...
      IsStop = FALSE;
      while( !IsStop )
      {
        FakeCoinWeight = 50 + rand( ) % ( 100 - 50 );
    	// 设置满足条件的伪币重量值 ...
    	if ( ( TrueCoinWeight > FakeCoinWeight ) && ( TrueCoinWeight - FakeCoinWeight <= 5 ) )
    	{
          IsStop = TRUE;
    
    	  *( p + kt ) = FakeCoinWeight;
    	}
      }
    
      // 返回伪币位置 ...
      return kt;
    }
    
    // 计算数组中硬币重量和 ...
    int CalcCoinTotalWeight( int ArrayData[], int kb, int ke )
    {
      int i, TotalWeight = 0;
    
      for( i = kb; i <= ke; i++ )
        TotalWeight += ArrayData[ i ];
    
      return TotalWeight;
    }
    
    // 采用分治法找到伪币( 假定伪币一定存在且只有 1 枚 )
    // kb - (子)数组左边界( begin )
    // ke - (子)数组右边界( end )
    int FindFakeCoin( int ArrayData[], int kb, int ke )
    {
      int LWeight, RWeight;
      int flag = 0;
      CallTimes++;
      printf( "< 第 %d 次查找 > 
    ", CallTimes );
      printf("kb= %d,ke=%d
    ",kb,ke);
      LWeight = CalcCoinTotalWeight(ArrayData,kb,kb+(ke-kb)/2);
      RWeight = CalcCoinTotalWeight(ArrayData,(kb+(ke-kb)/2) + 1,ke);
      printf("LWeight = %d	", LWeight);
      printf("RWeight = %d
    ", RWeight);
      if(LWeight > RWeight ) 
    	{
    		if( ke == kb + 1)
    		{
    			return ke;
    		}
    	    printf("RF(%d,%d)
    ",kb+(ke-kb)/2+ 1,ke);
    		return FindFakeCoin(ArrayData,(kb+(ke-kb)/2) + 1,ke);
    	}
    	else
    	{
    		if(ke == kb +1)
    		{
    			return kb;
    		}
    		printf("LF(%d,%d)
    ",kb,kb+(ke-kb)/2);
    		return FindFakeCoin(ArrayData,kb,kb+(ke-kb)/2);
    	}
    }
    
    
    int main(void)
    {
      int ArrayData[ ARRAY_SIZE ];
      int i, k, FakeCoinPos;
    
      // 生成包含 'N' 个硬币重量的数组( 含 1 枚伪币 ), 并返回伪币位置 ...
      k = CreateRandomCoinWeightArray( ArrayData, ARRAY_SIZE );
    
      // 输出随机数组内容 ...
      printf( "< 生成的硬币重量数组值为( 含 1 枚伪币 ) > : 
    " );
      for( i = 0; i < ARRAY_SIZE; i++ )
        printf( "[%d]-%d
    ", i+1,ArrayData[ i ] );
      printf( "
    " );
      printf( "< 第 %d 枚为伪币 > 
    ", ( k + 1 ) );
      printf( "
    " );
    
      // 采用分治法找到伪币位置 ...
      FakeCoinPos = FindFakeCoin( ArrayData, 0, ARRAY_SIZE - 1 );
    
      printf( "< 找到第 %d 枚为伪币 > 
    ", ( FakeCoinPos + 1 ) );
      printf( "
    " );
    
      // 等待用户输入任意一键返回 ...
      system( "PAUSE" );
      return 0;
    }
    
    


  • 相关阅读:
    【前缀和】【枚举倍数】 Codeforces Round #432 (Div. 2, based on IndiaHacks Final Round 2017) D. Arpa and a list of numbers
    【推导】【暴力】Codeforces Round #432 (Div. 2, based on IndiaHacks Final Round 2017) C. Five Dimensional Points
    【推导】Codeforces Round #432 (Div. 2, based on IndiaHacks Final Round 2017) B. Arpa and an exam about geometry
    【推导】【模拟】AtCoder Regular Contest 082 F
    【计算几何】【推导】【补集转化】AtCoder Regular Contest 082 E
    【推导】AtCoder Regular Contest 082 D
    【推导】【分类讨论】Codeforces Round #431 (Div. 1) B. Rooter's Song
    【推导】【贪心】Codeforces Round #431 (Div. 1) A. From Y to Y
    【贪心】hdu6180 Schedule
    【启发式搜索】【A*算法】hdu6171 Admiral
  • 原文地址:https://www.cnblogs.com/haxianhe/p/9271080.html
Copyright © 2011-2022 走看看