c++ 贪心算法 删数问题&&线段覆盖问题

1)删数问题

问题描述:给定n位正整数a,去掉其中任意kn个数字后,剩下的数字按原次序排列组成一个新的正整数。对于给定的n位正整数a和正整数k,设计一个算法找出剩下数字组成的新数最小的删数方案。

输入:

6579431483

输出:

543148

2)线段覆盖

问题描述:在一维空间中告诉你N条线段的起始坐标与终止坐标,要求求出这些线段一共覆盖了多大的长度。

输入:

4//表示输入的线段个数

2 5//线段起始坐标 线段终止坐标

扫描二维码关注公众号,回复: 1011194 查看本文章

6 7

1 3

3 4

输出:

5

 
 

1.
#include <iostream>
using namespace std;
int main()
{
    long long a;
    int k;
    cin>>a;
    cin>>k;
    int arr1[100];
    int m=0;
    while(a){
        arr1[m] = a % 10;
        a = a / 10;
        m++;
    }
    int n = m;     //求得a的位数n
    int arr[100];
    for(int j=0;j<n;j++){
        arr[j] = arr1[n-1-j];  //将a按位从高到低存到数组中
    }

    while(k--){ //核心处理
        int i=0,j;
        while( i<n-1 && arr[i]<=arr[i+1]){ //如果前一个数字大于后一个数字while停止 在后面的else里面处理
            i++;
        }
        if( i==n-1 ){ //如果i等于数组的最后下标意味着这个数字为123456789这样顺序排列
            n--;
            while(k--) //对这种顺序数字的处理为从最后删数
                n--;
            break;
        }
        else{ //此时i位置的数字大于后面相邻的数字 便将i位置的数字删除
            for(j=i;j<n-1;j++){
                arr[j]=arr[j+1]; //从i位置开始 后一个数字依次往前移动
            }
            n--;
        }
    }

    for(int i=0; i<n; i++){
        cout<<arr[i];
    }
}


 但是对于删除数字之后开头是0的情况并没有处理……

2.
#include <iostream>
#include <stdlib.h>
using namespace std;
struct Line{
    int start;
    int ending;
};
void bubble(Line l[],int n){    //将线段按照起始点进行排序 起点小的在前面 如果起点相同则终点小的在前面
    for(int i=0;i<n;i++){
        for(int j=0;j<n-1-i;j++){
            if( l[j].start > l[j+1].start){  //比较起点
                Line temp;
                temp = l[j];
                l[j] = l[j+1];
                l[j+1] = temp;
            }
            if( l[j].start == l[j+1].start && l[j].ending > l[j+1].ending){ //起点相同时把终点小的排在前面
                int temp1;
                temp1 = l[j].ending;
                l[j].ending = l[j+1].ending;
                l[j+1].ending = temp1;
            }
        }
    }
}
int lineCover(Line l[],int n,int Length){ //贪心算法求得线段覆盖长度
    int length = Length;
    if(n==1){  //n为1的时候 总覆盖长度为这一条线段的长度
        return length;
    }
    for(int i=1;i<n;i++){
        if( l[i].start >= l[i-1].start && l[i].start <= l[i-1].ending && l[i].ending > l[i-1].ending){ //当前线段起点大于等于前一个线段的起点小于等于前一个线段的终点并且终点大于前一个线段的终点
            length += l[i].ending - l[i-1].ending; //总覆盖长度增加两线段终点只差
        }
        else if( l[i].start >= l[i-1].ending){ //当前线段的起点大于等于前一线段的终点
            length += l[i].ending - l[i].start;//总覆盖长度增加此线段的长度
        }
        else if( l[i].start >= l[i-1].start && l[i].ending < l[i-1].ending ){ //当前线段在前一条线段的区间内
            l[i].ending = l[i-1].ending; //将当前线段的终点改为前一线段的终点
        }
    }
    return length;
}

int main()
{
    int n;
    cin>>n;
    Line l[100];
    for(int i=0;i<n;i++){
        cin>>l[i].start>>l[i].ending;
    }
    bubble(l,n);
    int la = l[0].ending - l[0].start;
    int Length = lineCover(l,n,la);
    cout<<Length<<endl;

    system("pause");
    return 0;
}

总结:

第一题:贪心算法是每一次循环将a[i]>a[i+1]的这个a[i]去掉,要使的最后得到的结果最小就要使最高位的数字最小。但是仅仅是这样处理的话还不完善,当原来的数字就是从小到大顺序排列的时候,比如说123456789这样的数字就没法处理,这样的数字要从后面处理,保留前面较小的数字。

实验例题中543148并不是最优的答案,贪心算法的目的也不是求得最优解,是求得最优近似解。但是我在做的时候做出了431483相对来说比较合理的结果。还要当数字中0比较多的时候,就会出现首位是0的情况。

第二题:为了对线段的处理方便,先运用冒泡排序将线段按照起点从小到大排序,如果起点相同的话就将终点较小的排在前面。在运算的时候,每一条线段都跟它前面紧紧相邻的一条线段比较,比较起点的位置和终点的位置,一开始我在处理的时候只考虑到了两种情况:①当前线段起点大于等于前一个线段的起点小于等于前一个线段的终点并且终点大于前一个线段的终点,这时length = l[i].ending - l[i-1].ending ②当前线段的起点大于等于前一线段的终点

这时length = l[i].ending - l[i].start。

还有一种情况是当前线段起点大于前一线段的起点 终点小于前一线段的终点,也就是当前线段在前一线段的区间内,这是要把当前线段的终点变化成较大的终点值,否则答案会出错。


猜你喜欢

转载自blog.csdn.net/qq_41815015/article/details/80291895