Dynamic Programming(动态规划)

 

Question:

给定一个最大为10,000的整型序列(每个值的大小在0到100,000)之间,求最大递减子序列。子序列可以不连续。

 

Answer1:

递归查找。递归查找从每个位置为开始的最长的递减子序列。

效率低!

Answer2:

当从前向后难找到节约方法时,从后向前的方法此时通常会富有成效。

这里就可以从序列的最后开始向前……

(1)检查从当前位置到最后所有节点的bestsofar值。

This is fairly clearly an O(N 2) algorithm. Check out its code:

1  #include <stdio.h>
2  #define MAXN 10000
3  main () {
4      long num[MAXN], bestsofar[MAXN];
5      FILE *in, *out;
6      long n, i, j, longest = 0;
7      in = fopen ("input.txt", "r");
8      out = fopen ("output.txt", "w");
9      fscanf(in, "%ld", &n);
10      for (i = 0; i < n; i++) fscanf(in, "%ld", &num[i]);
11      bestsofar[n-1] = 1;
12      for (i = n-1-1; i >= 0; i--) {
13          bestsofar[i] = 1;
14          for (j = i+1; j < n; j++) {
15              if (num[j] < num[i] && bestsofar[j] >= bestsofar[i])  {
16                  bestsofar[i] = bestsofar[j] + 1;
17                  if (bestsofar[i] > longest) longest = bestsofar[i];
18              }
19          }
20      }
21      fprintf(out, "bestsofar is %d\n", longest);
22      exit(0);
23  }

(2)跟上一个算法比,这个为了缩短检查时间,定义了bestrun[MAXN],其长度就是最长子序列长度,其值就是第一次存入的值(随后变为“最好的”值)

(原文:Implement an array `bestrun' whose index is the length of a long subsequence and whose value is the first (and, as it turns out, `best') integer that heads that subsequence.)

Here's a coding of this algorithm:

1  #include <stdio.h>
2  #define MAXN 200000//使用200000会堆栈溢出,而且题目要求也是20000,因此应改为20000。
3  main () {
4      FILE *in, *out;
5      long num[MAXN], bestrun[MAXN];
6      long n, i, j, highestrun = 0;
7      in = fopen ("input.txt", "r");
8      out = fopen ("output.txt", "w");
9      fscanf(in, "%ld", &n);
10      for (i = 0; i < n; i++) fscanf(in, "%ld", &num[i]);
11      bestrun[0] = num[n-1];
12      highestrun = 1;
13      for (i = n-1-1; i >= 0; i--) {
14          if (num[i] < bestrun[0]) {
15            bestrun[0] = num[i];
16            continue;
17        }
18        for (j = highestrun - 1; j >= 0; j--) {
19            if (num[i] > bestrun[j]) {
20                if (j == highestrun - 1 || num[i] < bestrun[j+1]){
21                    bestrun[++j] = num[i];
22                    if (j == highestrun) highestrun++;
23                    break;
24                }
25            }
26        }
27      }
28      printf("best is %d\n", highestrun);
29      exit(0);
30  }

 

(3)使用二分查找改进速度,使时间复杂度变为O(nlgn)

#include <stdio.h>
#define SIZE 200000
#define MAX(x,y) ((x)>(y)?(x):(y))

int     best[SIZE];        // best[] holds values of the optimal sub-sequence

int
main (void) {
    FILE *in  = fopen ("input.txt", "r");
    int i, n, k, x, sol;
    int low, high;

    fscanf (in, "%d", &n);	// N = how many integers to read in
    // read in the first integer
    fscanf (in, "%d", &best[0]);
    sol = 1;
    for (i = 1; i < n; i++) {
        best[i] = -1;
    	  fscanf (in, "%d", &x);

        if(x >= best[0]) {
          k = 0;
          best[0] = x;
        }
        else {
          // use binary search instead
          low = 0;
          high = sol-1;
          for(;;) {
            k = (int) (low + high) / 2;
            // go lower in the array
            if(x > best[k] && x > best[k-1]) {
              high = k - 1;
              continue;
            }
            // go higher in the array
            if(x < best[k] && x < best[k+1]) {
              low = k + 1;
              continue;
            }
            // check if right spot
            if(x > best[k] && x < best[k-1])
              best[k] = x;
            if(x < best[k] && x > best[k+1])
              best[++k] = x;
            break;
          }
        }
	      sol = MAX (sol, k + 1);
    }
    printf ("best is %d\n", sol);
    fclose(in);
    return 0;
}
posted @ 2011-04-26 21:43  记录点滴  阅读(817)  评论(0编辑  收藏  举报