最长上升子序列的回溯 ZOJ 2432

题目大意:

找一组最长上升公共子序列,并把任意一组满足的情况输出出来

 

最长公共上升子序列不清楚可以先看这篇文章

http://www.cnblogs.com/CSU3901130321/p/4182618.html

 

然后在这基础上加回溯,我自己一开始利用两个一维数组写回溯,测了很多数据都没问题

但一直给segment fault,网上也看到有人跟我一样说不知道为什么,一维数组的代码主要函数先放在这里留待以后看能否解决,或者有大神帮忙解决

 1 int dp[N] , a[N] , b[N] , rec[N] , fa[N] , src[N] , maxn , cnt;

 2 

 3 void LCIS(int m , int n)

 4 {

 5     memset(dp , 0 , sizeof(dp));

 6     memset(src , 0 , sizeof(src));

 7     memset(fa , 0 , sizeof(fa));

 8     for(int i = 1 ; i<=m ; i++){

 9         int  k = 0;

10         for(int j = 1 ; j<=n ; j++){

11             if(a[i] == b[j]){

12                 if(dp[j] < dp[k] + 1){

13                     dp[j] = dp[k] + 1;

14                     src[j] = i;

15                     fa[i] = src[k];

16                 }

17             }

18             if(a[i] > b[j] && dp[k] < dp[j]) k = j;

19         }

20     }

21 

22     maxn = 0 , cnt = 0;

23     int s;

24     for(int i = 1 ; i <= n ; i++)

25     {

26         if(maxn < dp[i])

27             maxn = dp[i] , s = src[i];

28     }

29     rec[cnt++] = s;

30     while(fa[s]){

31         rec[cnt++] = fa[s];

32         s = fa[s];

33     }

34 }
View Code


后来自己改成了二维数组来回溯

 1 #include <cstdio>

 2 #include <cstring>

 3 #include <iostream>

 4 using namespace std;

 5 const int N = 1005;

 6 #define max(a,b) a>b?a:b

 7 int dp[N] , a[N] , b[N] , rec[N] , maxn , cnt;

 8 int s[N][N]; //用来回溯,记录前一次出现最大的j的位置,因为那个位置一定是会出现b[pos] = 某个a[i]的

 9 

10 void TraceBack(int i , int j)

11 {

12     if(i < 1 || j < 1) return ;

13    // cout<<"here: "<<i<<" "<<s[i][j]<<endl;

14     if(s[i][j] >= 0){

15         rec[cnt++] = i;

16 

17         TraceBack(i-1 , s[i][j]);

18     }else TraceBack(i-1 , j);

19 }

20 

21 void LCIS(int m , int n)

22 {

23     memset(dp , 0 , sizeof(dp));

24     memset(s , -1 , sizeof(s));

25     for(int i = 1 ; i<=m ; i++){

26         int  k = 0;

27         for(int j = 1 ; j<=n ; j++){

28             if(a[i] == b[j]){

29                 if(dp[j] < dp[k] + 1){

30                     dp[j] = dp[k] + 1;

31                     s[i][j] = k;//记录上一次出现在最长子序列中能够进行匹配的j的位置

32                 }

33             }

34             if(a[i] > b[j] && dp[k] < dp[j]) k = j;

35         }

36     }

37 

38     maxn = 0 , cnt = 0;

39     int pos ;

40     //我自己写的函数原因,所以必须找到第一个出现最大值的位置pos,保证在这个位置会出现某个a[i]与其匹配

41     /*这里从后往前找和从前往后找效果一样,但是输出的序列可能不同,

42     但是题目要求只输出一种情况所以也没问题,方向找,输出的正好是样例的结果

43     for(int i = 1 ; i<=n ; i++) 也确实AC了没问题

44     */

45     for(int i = n ; i >= 1 ; i--)

46     {

47         if(maxn < dp[i])

48             maxn = dp[i] , pos = i;

49     }

50     TraceBack(m , pos);

51 }

52 

53 int main()

54 {

55     int m , n , T;

56     scanf("%d" , &T);

57     while(T--){

58         scanf("%d" , &m);

59         for(int i = 1 ; i<=m ; i++)

60             scanf("%d" , a+i);

61 

62         scanf("%d" , &n);

63         for(int i= 1 ; i<=n ; i++)

64             scanf("%d" , b+i);

65 

66         LCIS(m , n);

67 

68         printf("%d\n" , maxn);

69         for(int i = cnt - 1 ; i>=0 ; i--)

70             printf("%d " , a[rec[i]]);

71         printf("\n");

72         if(T>0) puts("");

73     }

74     return 0;

75 }

 

你可能感兴趣的:(ZOJ)