前面寫了最長公共子序列的問題。然后再加上自身對動態規划的理解,真到簡單的DP問題很快就解決了。其實只要理解了動態規划的本質,那么再有針對性的去做這方的題目,思路很快就會有了。不錯不錯~加油
題目描述:POJ2533
給出一個數列,找出這個數列中最長上升子序列中所包含的個數。
解題思路:
DP問題解題的一般方法就是自下而上,即先求解小的問題,然后再根據小的問題來解決大的問題,最后得到解。但是這里還要滿足的條件是最優子結構,即最優解包含着其子問題的最優解。
那么我們首先用arr[]數組(從0下標開始)存儲要求的數列,用longest_num[i]數組來記錄以i為結尾的子序列里面包含的最長上升子序列的數字個數。然后用循環控制,從下標為1開始求longest_num,並且記錄找到的最大值,即可得到解。在我的程序里面,我還加了一個功能就是把最長上升子序列打印出來,如果存在有多個的話,那么就只打印最后一個。
最后根據下面的DP方程就可以進行求解了:
longest_num[i] = max{longest_num[j] + 1,longest_num[i]} 其中j < i && arr[j] < arr[i]
程序:
#include <stdio.h> #define MAX_N 1001 int arr[MAX_N]; int longest_num[MAX_N]; int bt[MAX_N]; int max_point = 0; int LIS(int n) { int max = 1; //最長上升子序列的個數 int i,j; for (i = 0; i < n; i++) //i下標之前(包括i)的最長上升子序列的個數 { longest_num[i] = 1; } for (i = 0; i < n; i++) //用於回溯 { bt[i] = -1; } for (i = 1; i < n; i++) { for (j = 0; j < i; j++) { if (arr[i] > arr[j] && longest_num[i] < longest_num[j] + 1) { longest_num[i] = longest_num[j] + 1; if (longest_num[i] >= max) { max = longest_num[i]; max_point = i; bt[i] = j; } } } } return max; } void backtrack(int point) { if (-1 == bt[point]) { printf("%d ",arr[point]); return; } else { backtrack(bt[point]); printf("%d ",arr[point]); } } int main() { int n,i,ret; FILE *fp; fp = fopen("in.txt","r"); if (fp == NULL) { printf("fopen error!\n"); return -1; } fscanf(fp,"%d",&n); for (i = 0; i < n; i++) { fscanf(fp,"%d",&arr[i]); } ret = LIS(n); printf("%d\n",ret); backtrack(max_point); printf("\n"); return 0; }
2013/8/16 16:21
測試數據:
7 1 7 3 5 9 4 8
測試結果: