假币问题(二分法与三分法实现)

#include <iostream>
#include <math.h>

using namespace std;

#define numnum 14
int coin[numnum] = {2,2,2,2,2,2,2,2,2,2,1,2,2,2};

/*计算总重量 */
int Weight_Sum(int arr[], int low, int high)
{
    int sum = 0;
    for (int i = low; i <= high; i++)
        sum += arr[i];
    return sum;
}

/* 二分法,找出假币数组下标*/
int Weight_Coin2(int coin[], int coinNum, int low, int high)
{
    int mid = coinNum/2;          //计算中值
    int r = coinNum % 2;    //求余数,分别处理奇数偶数情况
    if (r == 0)                //当硬币刚好分为两组时
    {
        int index = 0;
        int A, B;
        A = Weight_Sum(coin, low, low + mid - 1);
        B = Weight_Sum(coin, low + mid, high);

        if (coinNum == 2)
        {
            if(A<B){
                index = low;
            }else{
                index = low+1;
            }
            return index;
        }
        else
        {
            if (A > B)
            {
                index = Weight_Coin2(coin, mid, low + mid, high);
                return index;
            }
            else
            {
                if(A==B){
                    return high;
                }
                index = Weight_Coin2(coin, mid, low, mid - 1);
                return index;
            }
        }
    }

    if (r == 1)           //处理奇数情况
    {
        int index = high;
        int A, B;
        A = Weight_Sum(coin, low, low + mid - 1);
        B = Weight_Sum(coin, low + mid, high-1);    //保证ab两个组硬币个数相同

        if (coinNum == 3)           //当硬币为三个分组时的处理
        {
            if(A==B){
                return high;
            }else if(A<B){
                return low;
            }else{
                return low+1;
            }
        }
        else
        {

            if (A == B)       //当两组硬币的重量相等时
            {
                index = high;
                return index;
            }
            else if (A<B)       //假币在A组中的情况
            {
                index = Weight_Coin2(coin, mid, low, low+mid-1);
                return index;
            }
            else       //假币在b组中的情况
            {
                index = Weight_Coin2(coin, mid, mid, high-1);
                return index;
            }
        }
    }

    return 0;
}

/* 三分法,找出假币数组下标*/
int Weight_Coin(int coin[], int coinNum, int low, int high)
{
    int k = floor(coinNum / 3);     //向下取整对硬币进行分组
    int r = coinNum % 3;            //求余数,目的是为了对其进行减治解决
    if (r == 0)                     //恰好分为三组的情况
    {
        int index = 0;              //假币的下标
        int A, B, C;                //分别存储三组硬币的重量
        A = Weight_Sum(coin, low, low + k - 1);                 //划分,数组下标从0开始
        B = Weight_Sum(coin, low + k, low + 2 * k - 1);
        C = Weight_Sum(coin, low + 2 * k, high);

        if (coinNum == 3)                 //当只剩下三个硬币时
        {
            if (A == B)                   //如果前两组硬币的值相等,说明第三组是假币,返回第三个硬币的下标
            {
                index = high;
            }
            else if (A == C)
            {
                index = high - 1;
            }
            else
            {
                index = low;
            }
            return index;
        }
        else           //多于三个硬币的情况
        {
            if (A == B)            //假币在第三组,处理方法和上面的相同
            {
                index = Weight_Coin(coin, k, low + 2 * k, high);
                return index;
            }
            else if (A == C)
            {
                index = Weight_Coin(coin, k, low + k, low + 2 * k - 1);
                return index;
            }
            else
            {
                index = Weight_Coin(coin, k, low, k - 1);
                return index;
            }
        }
    }

    if (r == 1)                    //当分组的时候恰好多出一枚硬币的情况处理
    {

        int index = high;          //index的值为high,与上面的index=0的区别所在
        int A, B, C;
        A = Weight_Sum(coin, low, low + k - 1);             //分别求三组硬币的重量
        B = Weight_Sum(coin, low + k, low + 2 * k - 1);
        C = Weight_Sum(coin, low + 2 * k, high - 1);         //划分三组,多了一个硬币,所以把最后一个硬币单独作为一组
        if (coinNum == 1)               //当只剩下一个硬币的时候,这个硬币即为假币,返回它的下标
        {
            return index;
        }
        else              //硬币个数多于一个时
        {
            if (A == B)
            {
                if (A == C)          //但三组硬币的重量相等,则说明最后一枚硬币为假币,返回其下标
                    return index;
                if ((A < C || A > C))         //另外的一种情况,假币在c组中
                {
                    index = Weight_Coin(coin, k, low + 2 * k, high - 1);
                    return index;
                }
            }
            else if (A == C)       //假币在b组中
            {
                index = Weight_Coin(coin, k, low + k, low + 2 * k - 1);
                return index;
            }
            else          //假币在a组中
            {
                index = Weight_Coin(coin, k, low, k - 1);
                return index;
            }
        }
    }
    if (r == 2)          //当恰好多出两个硬币的情况
    {
        int index = 0;                //设置三个index,与上面的分别设置index为0和high的区别
        int index1 = high - 1;
        int index2 = high;
        int A, B, C;
        A = Weight_Sum(coin, low, low + k - 1);
        B = Weight_Sum(coin, low + k, low + 2 * k - 1);
        C = Weight_Sum(coin, low + 2 * k, high - 2);           //划分三组,多余的两个硬币另外考虑
        if (coinNum < 3)           //当硬币少于三个不能分组时的处理
        {
            int campare1; //参照物
            if (high != numnum - 1)             //代码核心所在,当硬币不在分组中时
                campare1 = coin[numnum - 1];    //用最后一个数等于参照
            else
                campare1 = coin[0];             //用第一个数作为参照
            if (coin[high] == campare1)         //如果最大的数等于参照,说明这个硬币不是假币
                index = low;
            if (coin[low] == campare1)
                index = high;
            return index;
        }

        else     //当硬币个数大于三个的情况
        {
            if (A == B && B == C)       //当三组硬币的重量相等时
            {
                int cam = coin[0];      //用第一个硬币的重量作为参照物
                if (coin[high - 1] == cam)      //如果倒数第二个硬币的重量等于参照物,则返回最后一个硬币的下标
                    index = index2;
                if (coin[high] == cam)
                    index = index1;
                return index;
            }
            else if ((A == B) && (A < C || A > C))       //假币在c组中的情况
            {

                index = Weight_Coin(coin, k, low + 2 * k, high - 2);
                return index;
            }
            else if (A == C)       //假币在b组中的情况
            {
                index = Weight_Coin(coin, k, low + k, low + 2 * k - 1);
                return index;
            }
            else                   //假币在a组中的情况
            {
                index = Weight_Coin(coin, k, low, k - 1);
                return index;
            }
        }
    }
    return 0;
}


/*判断假币质量*/
void Judge(int number)
{
    int campareble;
    if (number != numnum - 1)
        campareble = coin[numnum - 1];
    else
        campareble = coin[0];
    if (coin[number] < campareble)
        cout << "假币的位置为 " << number+1 << "  并且假币偏轻" << endl;
    else if (coin[number] > campareble)
        cout << "假币的位置为 " << number+1 << "  并且假币偏重" << endl;
    else
        cout << "参照出错" << endl;
}


int main()
{
    int number;
    number = Weight_Coin(coin, numnum, 0, numnum - 1);
    //Judge(number);
    cout<<number<<endl;
    number = Weight_Coin2(coin,numnum,0,numnum-1);
    cout<<number<<endl;
    return 0;
}

展开阅读全文
©️2020 CSDN 皮肤主题: 1024 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值