1. 程式人生 > >3_尋找假幣問題(分治法)

3_尋找假幣問題(分治法)

題目

一個袋子裡有30個銀幣,其中一枚是假幣,並且假幣和真幣一模一樣,肉眼很難分辨,目前只知道假幣比真幣重量輕一點。
請問,如何區分出假幣?

分析

首先,分析一下尋找假幣問題,採用遞迴分治的思想求解。

  1. 首先為每個銀幣編號,然後將所有的銀幣等分為兩份,放在天平的兩邊。這樣就將區分30個銀幣的問題變為區別兩堆銀幣的問題。
  2. 因為假幣分量較輕,因此天平較輕的一側中一定包含假幣。
  3. 再將較輕的一側中銀幣等分為兩份,重複上述做法。
  4. 直到剩下兩枚銀幣,便可用天平直接找出假銀幣。

分治演算法思想

分治演算法的基本思想是將一個計算複雜的問題分為若干個規模較小、計算簡單的小問題來進行求解,然後綜合各個小問題,得到最終問題的答案。

執行過程如下:

  1. 對於一個規模為N的問題,若該問題可以容易的解決(比如說規模N較小),則直接解決,否則執行下面的步驟;
  2. 將該問題分解為M個規模較小的子問題,這些子問題應該互相獨立,並且與原問題形式相同;
  3. 遞迴求解各個子問題;
  4. 然後將各個子問題的解合併得到原問題的解;

使用分治演算法要求待求解的問題能夠化簡為若干個小規模的相同問題,通過逐步劃分,達到一個易於求解的階段而直接進行求解。然後再程式中使用遞迴演算法進行求解。

程式碼

#include <iostream>
#include <cstdlib>

using namespace std;

const
int MAXNUM = 30; int falseCoin(int weight[], int lhs, int rhs) { if (lhs == rhs) return lhs + 1; //如果只剩下兩個銀幣,則較輕的那個便是假幣 else if (lhs == (rhs - 1)) { return weight[lhs] < weight[rhs] ? lhs + 1 : rhs + 1; } int lsum = 0, rsum = 0; //如果偶數個銀幣,則比較兩等份 if ((rhs - lhs + 1
) % 2 == 0) { for (int i = lhs; i < (lhs + (rhs - lhs + 1) / 2); i++) { lsum += weight[i]; } for (int j = lhs + (rhs - lhs + 1) / 2; j <= rhs; j++) { rsum += weight[j]; } //左右兩份等重,則無假幣 if (lsum == rsum) return -1; else return (lsum < rsum) ? falseCoin(weight, lhs, lhs + (rhs - lhs) / 2) : falseCoin(weight, lhs + (rhs - lhs) / 2 + 1, rhs); } //如果奇數個銀幣,則比較除中間銀幣外的兩等份 else if ((rhs - lhs + 1) % 2 != 0) { for (int i = lhs; i < (lhs + (rhs - lhs) / 2); i++) { lsum += weight[i]; } for (int j = (lhs + (rhs - lhs) / 2 + 1); j <= rhs; j++) { rsum += weight[j]; } //左右兩份等重,則無假幣 if (lsum == rsum && weight[lhs] == weight[lhs + (rhs - lhs) / 2]) return -1; //如果兩份等重,中間銀幣較輕,則中間銀幣為假幣 else if (lsum == rsum && weight[lhs] > weight[lhs + (rhs - lhs) / 2]) return lhs + (rhs - lhs) / 2 + 1; //否則,返回較輕那份中的假幣 else return (lsum < rsum) ? falseCoin(weight, lhs, lhs + (rhs - lhs) / 2 - 1) : falseCoin(weight, lhs + (rhs - lhs) / 2 + 1, rhs); } } int main() { int weight[MAXNUM]; int n; while (cin >> n) { for (int i = 0; i < n; i++) cin >> weight[i]; int falsePos = falseCoin(weight, 0, n - 1); if (falsePos != -1) cout << "第" << falsePos << "個銀幣為假幣!" << endl; else cout << "無假幣!" << endl; }//while system("pause"); return 0; }

相關推薦

3_尋找假幣問題治法

題目 一個袋子裡有30個銀幣,其中一枚是假幣,並且假幣和真幣一模一樣,肉眼很難分辨,目前只知道假幣比真幣重量輕一點。 請問,如何區分出假幣? 分析 首先,分析一下尋找假幣問題,採用遞迴分治的思想求解。 首先為每個銀幣編號,然後將所有的銀幣等分為兩份,

C語言實現快速排序法治法

下一個 enter hang partition 等於 就是 tor log markdown title: 快速排序法(quick sort) tags: 分治法(divide and conquer method) grammar_cjkRuby: true ---

合並排序治法

for 數組 數組a 想要 -s fin size 外部 ... 使用分治法進行合並排序,問題描述參見:https://www.cnblogs.com/jingmoxukong/p/4308823.html 算法核心: //merge_sort.h #ifndef

快速排序治法

ios type font nbsp def 註意 class 裏的 span 問題描述參考:http://blog.csdn.net/code_ac/article/details/74158681 算法實現部分: //random_quick_sort.cpp

平面最接近點對問題治法

技術 src void emp image mage tar 分治 pac 問題描述參見:https://www.cnblogs.com/zyxStar/p/4591897.html 代碼參考:http://blog.csdn.net/qq_28666193/articl

Codeforces 448C Painting Fence治法

劃分 .com 規劃 == sum tps codeforce nbsp 長度 題目鏈接:http://codeforces.com/contest/448/problem/C 題目大意:n個1* a [ i ] 的木板,把他們立起來,變成每個木板寬為1長為 a [ i

歸併排序治法

橫向想了一下這幾個經典的排序演算法,個人感覺快排應該是速度最快了,首先快排在空間複雜度的角度應該開銷比歸併要小很多,因為歸併需要申請新的臨時空間,時間複雜度上雖說都是N*log(n)。但是同一個數量級上歸併有很多的陣列複製操作,感覺如果資料很大的話應該比快排所消耗的時間多很多(但是都是在一個數量級上,比如10

Java實現快速排序治法

<span style="font-size:18px;">package com.alibaba; public class QuickSortTest { public stati

最大連續和治法O(nlogn)

分解:將序列分解成元素個數儘量相等的子序列,求出每個子序列的最大連續和 合併:合併子問題得到原問題的解,由於最大連續和的子序列要麼完全在中點左邊,要麼完全在中點右邊,要麼就是橫跨左右兩邊,所以比較這幾

演算法設計--眾數和重數問題治法

問題描述: 給定含有n個元素的多重集合S,每個元素在S中出現的次數稱為該元素的重數。多重集S中重數最大的元素稱為眾數。例如,S={1,2,2,2,3,5}。多重集S的眾數是2,其重數為3。對於給定的n

計算最大子段治法

這個程式使用分治法計算最大子段,結果為最大子段之和,用遞迴程式實現。 原始資料使用隨機函式生成。 採用結構化程式設計,可以很容易改為從標準輸入或檔案讀入資料,只需要修改函式getData即可。 資料個數由巨集定義給出,也可以輕鬆地改為輸入。 /* * 最大子段演算法程

冪取模 治法

int pow_mod(int a,int n,int m )       //a^n % m {     if(n == 1) return a % m;     int x = pow_mod(a,n/2,m);     long long ans = (long lo

UVA - 1608 Non-boring sequences治法

name 表示 urn its mes else pac 學習 tro 題目: 如果一個序列的任意連續的子序列中至少有一個只出現一次的元素,則稱這個序列是不無聊的。輸入一個n(n≤200000)個元素的序列A(各個元素均為109以內的非負整數),判斷它是不是不無聊的。 思路

LeetCode 之 Pow(x, n)治法

【問題描述】 Implement pow(x, n). 1.【基礎知識】 1)分治的意識,一道O(N)的演算法題,琢磨出O(lgN)的思想出來就是要求; 2.【屌絲程式碼】 卡殼的地方: 1.Time Limit Exceeded。 #include <vecto

矩陣相乘治法

一個簡單的分治演算法求矩陣相乘 C=A * B ,假設三個矩陣均為n×n,n為2的冪。可以對其分解為4個n/2×n/2的子矩陣分別遞迴求解: 遞迴分治演算法: 演算法中一個重要的細節就是在分塊的時候,採用的是下標的方式。 #include &

格雷碼生成治法

lose def rev can i++ stdlib.h 輸入一個數 txt urn 1 #include<stdio.h> 2 #include<math.h> 3 #include<stdlib.h> 4 #def

矩陣相乘問題治法求解

採用蠻力+分治進行求解: 矩陣相乘公式: 程式碼: public class Matrix { //初始化一個隨機nxn階矩陣 public static int[][] initializationMatrix(int n){

排序問題蠻力法,治法

蠻力法: 選擇排序法: 演算法思想:在剩餘序列中選出最小(或最大)的關鍵字,和剩餘序列的第一個關鍵字交換位置,依次選擇下去(每次掃描結束找出最小的一個元素依次放在前面的位置),直至使整個序列有序。 程式碼實習: #include<iostream> using names

資料結構與演算法- 五大常用演算法總結治法,回溯法,分治限界法,貪心演算法,動態規劃法

1.分治法(Recurrence and Divide-Conquer)        對於一個規模為n的問題,若該問題可以容易解決(比如說規模n較小)則直接解決,否則將其分解為k個規模較小的子問題,這些子問題互相獨立且與原問題形式相同,遞迴地解決這些子問

ADA演算法知識Divide and conquer algorithm治法解決最大子陣列和問題

[Maximum Subarry Sum] The maximum subarry sum problem takes as input an array of (positive or negative) integers a[1..n] and returns the largest sum o