贪婪算法-可绝对贪婪问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36292543/article/details/84000982

目录

题目描述

问题分析

算法设计

代码编写 

打印结果


 题目描述

键盘输入一个高精度的正整数n,去掉其中任意s个数字后剩下的数字按原左右次序将组成一个新的正整数。编程对给定的n和s,寻找一种方案使得剩下的数字组成的新数最小。

输出应包括所去掉的数字的位置和组成的新的整数(n不超过240位) 。

问题分析

在位数固定的前提下,让高位的数字尽量小,那么值就较小。

总目标:删除高位较大的数字,相邻两位比较。若高位比低位大,则删除高位。


                                                                                 实例1:n = 12345863,s = 3

n = 1 2 4 3 5 8 6 3

4>3,删除4

1 2   3 5 8 6 3

8>6,删除8

1 2   3 5   6 3
6>3,删除6 1 2   3 5      
相邻的数字只需要从前向后比较

                                                                                实例2:n = 231183,s = 3

n = 2 3 1 1 8 3

3>1,删除3

2   1 1 8 3

2>1,删除2

    1 1 8 3
8>3,删除8     1 1   3
当第i位与第i+1位比较,若第i位删除,则必须向前考虑第i-1位与第i+1位进行比较。

                                                                                 实例3:n = 123456,s = 3

n = 1 2 3

4

5 6
相邻比较发现,一个数字都没有删除,所以这就要考虑将后3位删除。在删除过程中也可能有这种情况出现:132567-->12567

                                                                                   实例4:n = 120083,s = 3

n = 1 2 0 0 8 3

2>0,删除2

1   0 0 8 3

1>0,删除1

    0 0 8 3
8>3,删除8     0 0   3

1、删除一些数字后,高位可能出现‘0’,直接输出这个数据不合理。要将结果中的数字‘0’全部删除掉再输出。

2、若全是‘000000’,则要保留最后一个‘0输出’。


数据结构设计 

对于高精度整数,可以将其存储为字符串格式。

算法设计

由实例归纳算法。

算法注意由4部分组成:初始化,相邻数字比较(必要时删除),处理比较过程中删除位数不够s位情况和结果输出。

其中删除字符的实现方法很多:如

1.物理的进行字符删除,就是用后面的字符覆盖已删除的字符,字符串的长度改变,这样可能会有较多的字符移动操作,算法效率不高。

2.可以利用数字记录字符的存在状态,元素值为“1”表示对应的数值存在,0表示不存在。 但这样做前后数字的比较过程和最后的输出过程相对复杂些。

3,利用一个数组,来记录为删除字符的下标。删除值时对应数组的下标删除。

代码编写 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void Delete(char n[], int b, int k) {
	int i;
	printf("11111  strlen(n)= %2d\n", strlen(n));
	for(i=b; i<=strlen(n)-k; i=i+1)
		n[i]=n[i+k];
}

int main( ) {
	char  n[100]="12435833";
	int s=3,i,j,j1,c,data[100],len;
	printf("%c", n[8]);
	len=strlen(n);
	printf("$\n");

	j1=-1;  //记录上一个被删除的元素的位置,用来辨别是删除上一个被删除元素右边的元素还是左边的元素
	for (i=0; i<s; i=i+1) {
		int len1=strlen(n);
		for (j=0; j<len1-1; j=j+1)
			if (n[j]>n[j+1]) {              //贪婪选择
				Delete(n,j,1);
				printf("##### j= %d  j1= %d  i= %d  strlen(n)-1= %2d\n",  j, j1, i, strlen(n)-1);
				if (j>=j1)       // 说明即将被删除的元素位于上一个被删除元素的右边
					data[i]=j+i;  //删除上一个被删除元素右边的元素        //记录删除数字位置
				else                                //实例2向前删除的情况实例
					data[i]=data[i-1]-1;    ////删除上一个被删除元素左边的元素
				j1=j;
				break;
			}
		printf("j= %d  j1= %d  i= %d  len1= %d strlen(n)= %d\n",  j, j1, i, len1, strlen(n));
		if( j>=len1-1)   //说明在给定的序列中,任意相邻的两个元素,总是后面的元素大于前面的元素,
			break;            //即序列中的元素是按照从小到大排列的, 一旦是这种情况,就直接从后向前删除 s 位数即可。
	}

	printf("Output ***  data[]:\n");
	for (int i=0; i<s; i=i+1)
		printf("%2d ", data[i]);

	printf("22222  strlen(n)= %2d len= %d  i= %d\n",   strlen(n), len, i);
	for (i=i; i<s; i=i+1) { //当序列中的元素是有序(从小到大排列)的, 直接从后向前删除 s 位数即可。
		j=len-1-i;
		Delete(n,j,1);
		data[i]=j;
	}

	while (n[0]=='0' && strlen(n) >1)
		Delete(n,0,1);
	//将字符串首的若干个“0”去掉       print(n);
	printf("Output array data[]:\n");
	for (i=0; i<s; i=i+1)
		printf("%2d ", data[i]);

	printf("\n Output array n[]:\n");
	printf("33333   strlen(n)= %2d\n",   strlen(n));
	for (i=0; i<strlen(n); i=i+1)
		printf("%c  ", n[i]);

	system("pause");
	return 0;
}

打印结果

猜你喜欢

转载自blog.csdn.net/qq_36292543/article/details/84000982