问题描述:
8.[J.UIlman]给定一个n元实数集合,一个实数t和一个整数k,如何快速确定是否存在一个k元子集,其元素之和不超过t?
问题解析:
1、 本题问题清晰,不会产生什么歧义,要找到该k元子集,那么首先就是要找到n元实数里所有的小于实数t的数,这自然就想到了排序最为方便!
2 、排序之后,看前k个数之和与n进行比较,就能够得到!
解决方案:
下面是测试代码:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
#include <cstdio>
#include <cstdlib> // qsort #include <cmath> // ceil #include <cstring> // strlen #include <cassert> // assert #define MAXLENGTH 10 // 数组长度 #define error( str ) fatal_error( str ) #define fatal_error( str ) fprintf( stderr, "%s\n", str ), exit( 1 ) int floatcomp( const void* a, const void* b) { int val = ceil( *( float*)a - *( float*)b ); // 向上取整 return val; } /************************************************************************/ // 函数名称:find_subset // 函数目的:在arr查找中查找k元子集之和不超过t // 函数参数:arr:数组 arrsize:数组长度,t:实数 K 子集个数 // 函数返回:无 // 使用条件:K > 0 /************************************************************************/ void find_subset( float* arr, int arrsize, float t, int k) { assert(k > 0); // 先升序 qsort(arr, arrsize, sizeof( float), floatcomp); float m = 0. 0; int point = - 1; // 临界点 for ( int i = 0; i < arrsize; ++i){ if ((m += arr[i]) > t){ point = i; break; } } if ( point >= k ){ printf( "存在一个%d元子集,下面%d个里面的任意%d个元素都满足该条件:\n", k, point, k); for ( int i = 0; i < point; ++i){ printf( "%.1f\t", arr[i]); } } else{ printf( "Sorry,不存在这样的%d元子集\n", k); } return; } int main() { float arr[MAXLENGTH] = { 10, 6. 1, 3. 4, 4, 5. 0, 2, 7, 8, 9. 2, 1. 7}; find_subset(arr, MAXLENGTH, 31. 3, 5); return 0; } |
心得疑惑:
1、作者又提出问题:设计出时间复杂度分别为O(nlogk)、O(nk)、O(n2)、O(nk)的自然算法。
2、本题可以让加深对运行时间的概念。