算法分析:假币寻找问题 分治法 JAVA

【假币寻找】有n枚外形相同的硬币,其中有一枚是假币,假币的重量比真币轻,但是目前仅有一台无砝码的天平。请设计一个算法,要求用最少的天平使用次数找出这枚假币。

算法设计思路

将硬币的数量除以3,分为4组,A、,B、C组和余数组,然后A组和B组相互测量

如果A比B重或者B比A重,则选出较轻的一组,则假币范围缩小到较轻的那一组;如果A、B组的重量是一样的,则假币范围缩小在C组和余数组,再将C与A或者B作比较,若C与A或B的重量一样,则假币范围缩小到余数组。

找到范围后,继续递归分组,直到需比较的硬币数为1或者2或者3时,1时直接输出,2和3时作比较即可。

算法实现的伪代码

算法coinCompare ( int[ ] cArr,  int first,  int end )

输入:硬币数组,首位下标,末位下标

输出:假币所在的下标

  1. if ( end – first == 0 )
  2.     输出下标
  3. if(end – first == 1)
  4.     比较之后输出下标
  5. if(end – first == 2)
  6.     比较之后输出下标
  7. if ( end – first > 3 )
  8.     int each = 每段分割的长度
  9.     a[2] b[2] c[2] yu[2] 分别储存每段的首尾
  10.     big[ ] = coinAdd( a, b, c, yu, cArr, first, end )
  11.     coinCompare( cArr , big[0] , big[1] )

算法coinAdd ( input  a[ ],  input  b[ ],  input  c[ ] , input  yu[ ] , input  cArr[ ], input  first , input  end)

输入:a组,b组,c组,余数组,原数组,首位,末尾

输出:假币所在数组

S1: 将a组的数加起来

S2: 将b组的数加起来

S3: 将c组的数加起来

S4: 将yu组的数加起来

S5: 比较每个数组加起来的大小

S6: if( 数组加起来的大小比较小 )

S7:     return 该数组

实现代码

import java.util.Random;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int[] cArr = new int[n];
        Random r = new Random();
        for (int i = 0; i < cArr.length; i++) { //赋初值0, 真币为0, 假币为1
            cArr[i] = 0;
        }

        cArr[r.nextInt(cArr.length)] = 1; //加入假币

        coinCompare(cArr, 0, n - 1); //查找假币

    }

    public static void coinCompare(int[] cArr, int first, int end) { //查找假币
      if (end - first == 0) { //如果区间为1则直接输出
                System.out.println(first);
        } else if (end - first == 1) { //如果区间为2则比较,输出假币
            if (cArr[first] > cArr[end])
                System.out.println(first);
            else
                System.out.println(end);
        } else if (end - first == 2) { //如果区间为3则比较,输出假币
            if (cArr[first] == cArr[first + 1]) {
                System.out.println(end);
            } else if (cArr[first] > cArr[first + 1]) {
                System.out.println(first);
            } else
                System.out.println(first + 1);
        } else { //如果区间大于3,则进行分割

            int each = (((end - first) + 1) - ((end - first) + 1) % 3) / 3; //取分割长度
            int[] a = new int[2]; //a,b,c,yu数组分别记录每段区间的首尾
            int[] b = new int[2];
            int[] c = new int[2];
            int[] yu = new int[2];

            a[0] = first;
            a[1] = first + each - 1;

            b[0] = a[1] + 1;
            b[1] = b[0] + each - 1;

            c[0] = b[1] + 1;
            c[1] = c[0] + each - 1;

            if (((end - first) + 1) % 3 == 0) {
                yu[0] = -1;
                yu[1] = -1;
            } else {
                yu[0] = c[1] + 1;
                yu[1] = end;
            }

            int[] big = coinAdd(a, b, c, yu, cArr, first, end); //查找出假币所在的区间

            coinCompare(cArr, big[0], big[1]); //递归分割
        }
    }

    public static int[] coinAdd(int[] a, int[] b, int[] c, int[] yu, int[] cArr, int first, int end) { //选出假币区间,将区间的数全部加起来,找出等于1的区间

        int cA = 0, cB = 0, cC = 0, cYu = 0;

        for (int i = a[0]; i < b[0]; i++) {
            cA += cArr[i];
        }
        for (int i = b[0]; i < c[0]; i++) {
            cB += cArr[i];
        }
        if (yu[0] != -1) {
            for (int i = c[0]; i < yu[0]; i++) {
                cC += cArr[i];
            }

            for (int i = yu[0]; i < end + 1; i++) {
                cYu += cArr[i];
            }
        } else {
            for (int i = c[0]; i < end + 1; i++) {
                cC += cArr[i];
            }
            cYu = -1;
        }

        if (cA == cB) {
            if (cA == cC) {
                return yu;
            } else {
                return c;
            }
        }
        if (cA > cB) {
            return a;
        } else {
            return b;
        }
    }

}

写得不好,多请谅解!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值