现在的位置: 首页 > 综合 > 正文

算法研究(三) 巧用快排

2013年12月22日 ⁄ 综合 ⁄ 共 1546字 ⁄ 字号 评论关闭

题目:给定一个具有n个元素的实数集A,一个实数t,一个整数k,请问如何快速的确定该实数集中是否存在一个具有k个元素的子集,其所有元素之和小于等于t?

对于这个问题,我首先想到的是排序,只要找到实数集中最小的k个元素,问题也就解了。但对于完全的排序而言实际上是没有必要的,我们只需要确定最小的k个元素就行了。于是我又想到了快排,它的分治思想用在这里是再合适不过了,我们只需对快排作一些改造可以得到一个很好的解决方案。

  1. int partition(double *set, int n) {  
  2.   
  3.     int low = 0, high = n - 1;  
  4.     double p = set[n - 1];   
  5.     while(low < high) {  
  6.   
  7.         while(set[low] <= p && low < high )  
  8.             ++ low;  
  9.         if (low < high)  
  10.             set[high --] = set[low];  
  11.         while(set[high] > p && low < high)  
  12.             -- high;  
  13.         if (low < high)  
  14.             set[low ++] = set[high];  
  15.     }     
  16.     set[low] = p;  
  17.     return low;  
  18. }  
  19.   
  20. int sum(double* set, int n) {  
  21.           
  22.     int i;  
  23.     double s = 0;  
  24.     for (i = 0; i < n; ++i)  
  25.         s += set[i];  
  26.     return s;  
  27. }  
  28.   
  29. void print(double* set, int n) {  
  30.   
  31.     int i;  
  32.     for (i = 0; i < n; ++i)  
  33.         printf("%lf\t", set[i]);  
  34. }  
  35.   
  36. int verify(double *set, int n, int k, double t) {  
  37.   
  38.     if (n < k || n == 0)  
  39.         return 0;  
  40.   
  41.     int m = partition(set, n);  
  42.     if (0 == m)  
  43.         m = 1;  
  44.   
  45.     if (m <= k) {  
  46.         double s = sum(set, m);  
  47.         if (m < k) {  
  48.             if (s <= t) {  
  49.                 print(set, m);  
  50.                 return verify(set + m, n - m, k - m, t - s);  
  51.             }  
  52.             else  
  53.                 return 0;  
  54.         }  
  55.         else {  
  56.             if (s <= t) {  
  57.                 print(set, m);  
  58.                 printf("\n");  
  59.                 return 1;  
  60.             }  
  61.             else  
  62.                 return 0;  

抱歉!评论已关闭.