[算法设计与分析]4.4.1可绝对贪婪问题(高精度正整数删除s位使剩余最大+数列极差+埃及分数)

#include<cstdio>
#include<iostream>
#include<cstring>

using namespace std;

void deletes(char n[], int b, int k);
void ScanDelete(char n[]);

void Deletes(char n[]);

void ArrayRange();//数列极差
int calculatemin(int a[], int n);
int calculatemax(int a[], int n);
void max2(int a[], int n);
void min2(int a[], int n);
int s1, s2;


void EgyptFraction(int a, int b);//a和b分别作为分子和分母

const int N = 100;

int main ()
{
    char n[N] = "123456";//将大数存储在字符型数组中
    //ScanDelete(n);
    Deletes(n);

    ArrayRange();

    EgyptFraction(7, 8);
}

void Deletes(char n[])
{
    int s, data[100], len, i, j, j1;
    s = 3;

    len = strlen(n);
    if(s >= len)
    {
        cout << "data is error";
        return;
    }

    i = j = j1 = 0;
    while(i < s && j <= strlen(n) - 1)
    {//i代表删除位数 值从0开始
        while(n[j] <= n[j + 1])
            j++;
        if(j < strlen(n))//证明出现高位元素大于低位元素
        {
            deletes(n, j, 1);//可以直接删除
            if(j > j1)
                data[i] = j + i;
            else
                data[i] = data[i - 1] - 1;
            i++;
            j1 = j;
            j--;//进行删除操作之后需要对元素进行回溯 但只回溯一位即可 而不需要和另一个算法一样从头开始
        }
    }
    for(i = i; i <= s; i++)
    {
        j = len - i + 1;
        deletes(n, j, 1);
        data[i] = j;
    }

    while(n[0] == '0' && strlen(n) > 1)
    {//注意是‘0’ 因为n是字符型数组
        deletes(n, 0, 1);
    }
    for(i = 1; i <= s; i++)
        cout << data[i] << " ";
    cout << endl;

    for(i = 0; i < strlen(n); i++)
        cout << n[i] << " ";

    cout << endl;
}

void deletes(char n[], int b, int k)
{
    for(int i = b; i <= strlen(n) - k; i++)
        n[i] = n[i + k];
}

void ScanDelete(char n[])
{
    int s, i, j, j1, c, data[100], len;
    s = 3;//指定要删除的位数

    len = strlen(n);

    if(s >= len)
    {
        cout << "data is error";
        return;
    }

    j1 = 0;
    //删除策略:从高位开始判断 只要高位的数字大于与它直接相邻的低位数字 则低位数字可以直接删除
                //只要进行过一次删除操作 就需要重新从最高位开始扫描
    for(i = 1; i <= s; i++)
    {//因为data的作用是记录删除元素的位置 因此data数组的长度与s一致
        for(j = 0; j < strlen(n); j++)//n数组的下标从0开始有效
        {
            if(n[j] > n[j + 1])//即使是一个递增数列也可以进行删除 eg:123456 此时比较到最后成为6和0的比较 一样可以删除
            {
                //删除一共有两种可能 1.新删除的是上一次删除的元素的低端 此时两个元素之间的位置没有直接关系
                                        //eg:20031 第一次删除2但是第二次删除3
                                    //2.新删除的元素是上一次删除元素的高端 此时两者一定相邻 因为上一次删除操作之后
                                      //使上一次删除元素的右边元素发生变化 而左边的元素没有发生变化 因此若要删除
                                      //则一定是删除与上一次删除元素相邻的左端的元素 二者有直接的位置关系

                deletes(n, j, 1);//直接将较大的高位数字删除
                //j1中储存的是上一次删除元素的位置
                if(j > j1)//if条件成立说明新删除的元素的位置是在上一次删的元素的位置的低端
                    data[i] = j + i;//因为i是删除元素的个数 因此i+j就是在原数组中的位置
                else
                    data[i] = data[i - 1] - 1;//此时说明新删除的元素的位置是在上一次删除的元素的高端
                j1 = j;
                break;
            }
        }
         if(j > strlen(n))//需要在循环的累加条件执行之前就进行是否超出字符长度的判断 否则会出现数组访问溢出的现象!!
              {
                  break;
              }
    }
    for(i = i; i <= s; i++)
    {cout << "A";
        j = len - i + 1;
        deletes(n, j, 1);
        data[i] = j;
    }

    while(n[0] == '0' && strlen(n) > 1)
    {//注意是‘0’ 因为n是字符型数组
        deletes(n, 0, 1);
    }
    for(i = 1; i <= s; i++)
        cout << data[i] << " ";
    cout << endl;

    for(i = 0; i < strlen(n); i++)
        cout << n[i] << " ";

    cout << endl;

}

void ArrayRange()
{
    int j, n, maxs, mins;
    n = 3;//定义数列的有效长度
    int a[n + 1] = {0, 3, 5, 7};
    int b[n + 1];

    for(int i = 0; i <= n; i++)
    {
        b[i] = a[i];//将数组a中的元素拷贝到b中
    }
    mins = calculatemin(a, n);
    maxs = calculatemax(b, n);//一定要注意传入的是b 因为a的值已经被改变了
    cout << "max - min = " << maxs - mins << endl;
}

int calculatemin(int a[], int n)
{
    while(n > 2)
    {
        max2(a, n);
        a[s1] = a[s1] * a[s2] + 1;//将当前计算结果存储在s1中
        a[s2] = a[n];//用数列的最后一个数对s2进行覆盖
        n--;//数列长度-1
    }
    return (a[1] * a[2] + 1);//当循环结束的时候 有效数据就存储在1和2中
}

int calculatemax(int a[], int n)
{
    while(n > 2)
    {
        min2(a, n);
        a[s1] = a[s1] * a[s2] + 1;
        a[s2] = a[n];
        n--;
    }
    return (a[1] * a[2] + 1);
}

void max2(int a[], int n)
{
    int j;
    s1 = a[1] >= a[2] ? 1 : 2;//是s1中存储数列中最大的值的下标
    s2 = a[1] >= a[2] ? 2 : 1;//s2中存储第二大值的下标

    for(j = 3; j <= n; j++)
    {
        if(a[j] > a[s1])
        {
            s2 = s1;
            s1 = j;
        }
        else if(a[j] > a[s2])//a[s1]>a[j]>a[s2] 此时只需要将s2的值改为j
            s2 = j;
    }
}

void min2(int a[], int n)
{
    int j;
    s1 = a[1] <= a[2] ? 1 : 2;//此时s1中存储数列中最小元素的下标
    s2 = a[1] <= a[2] ? 2 : 1;//s2中存储数列中第二小元素的下标

    for(j = 3; j <= n; j++)
    {
        if(a[j] < a[s1])//a[j]<a[s1]<a[s2]
        {
            s2 = s1;
            s1 = j;
        }
        else if(a[j] < a[s2])//a[s1]<a[j]<a[s2]
            s2 = j;
    }
}


void EgyptFraction(int a, int b)
{
    int c;
    if(a >= b)
        printf("error");
    else if(a == 1 && b % a == 0)
        cout << a << " / " << b << " = 1 / " <<  b / a << endl;
    else
    {
        cout << a << " / " << b << " = ";
        while(a != 1)
        {
            c = b / a + 1;//模拟的是 a/b-1/c的结果
            a = a * c - b;
            b *= c;
            cout << " 1 / " << c;
            if(a > 1)
                cout << " + ";
            if(b % a == 0 || a == 1)//可以整除或者被除数为1
            {
                cout << " 1 / " << b / a;
                a = 1;
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值