[关闭]
@sensitive-cs 2017-05-16T12:05:01.000000Z 字数 2303 阅读 837

LIS学习以及模板

模板


先帖模板
nlogn:

  1. int stack[10010];
  2. int lis(int arr[],int n)
  3. {
  4. int i,top,mid,low,high;
  5. top = 0;
  6. stack[0] = -1;
  7. for(i=0;i<n;i++)
  8. {
  9. if(arr[i]>stack[top])
  10. stack[++top] = arr[i];
  11. else
  12. {
  13. low = 1;
  14. high = top;
  15. while(low <= high)
  16. {
  17. mid = (low + high)/2;
  18. if(arr[i] > stack[mid])
  19. low = mid + 1;
  20. else
  21. high = mid - 1;
  22. }
  23. stack[low] = arr[i];
  24. }
  25. }
  26. return top;
  27. }

此模板只能用于计算最长长度,无法打印序列。

n^2

  1. unsigned int LISS(const int array[], size_t length, int result[])
  2. {
  3. unsigned int i, j, k, max;
  4. //变长数组参数,C99新特性,用于记录当前各元素作为最大元素的最长递增序列长度
  5. unsigned int liss[length];
  6. //前驱元素数组,记录当前以该元素作为最大元素的递增序列中该元素的前驱节点,用于打印序列用
  7. unsigned int pre[length];
  8. for(i = 0; i < length; ++i)
  9. {
  10. liss[i] = 1;
  11. pre[i] = i;
  12. }
  13. for(i = 1, max = 1, k = 0; i < length; ++i)
  14. {
  15. //找到以array[i]为最末元素的最长递增子序列
  16. for(j = 0; j < i; ++j)
  17. {
  18. //如果要求非递减子序列只需将array[j] < array[i]改成<=,
  19. //如果要求递减子序列只需改为>
  20. if(array[j] < array[i] && liss[j] + 1> liss[i])
  21. {
  22. liss[i] = liss[j] + 1;
  23. pre[i] = j;
  24. //得到当前最长递增子序列的长度,以及该子序列的最末元素的位置
  25. if(max < liss[i])
  26. {
  27. max = liss[i];
  28. k = i;
  29. }
  30. }
  31. }
  32. }
  33. //输出序列
  34. i = max - 1;
  35. while(pre[k] != k)
  36. {
  37. result[i--] = array[k];
  38. k = pre[k];
  39. }
  40. result[i] = array[k];
  41. return max;
  42. }

此模板需要解释的地方是最后的输出序列,(其实就像链表
最开始的pre[0] = 0,其他的pos都跟pre[pos]不一样,因为肯定是有一个最长递增序列的。所以我们就要从后往前记录,这样才能用res数组顺序输出。

hdu 1160 fatmouse
题意:
一个耗子两个属性,一个体重,一个速度,我们要找一个最长的体重严格递增,速度严格递减的序列。
思路:
先对体重进行排序,然后对速度求lis
坑:开始的时候进行debug的时候,没有考虑体重也需要严格递增,其实判断的时候需要加体重严格递增的限制条件,恩。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. struct node
  6. {
  7. int p;
  8. int w,s;
  9. }m[1005];
  10. bool cmp(struct node a,struct node b)
  11. {
  12. return a.w < b.w;
  13. }
  14. int pre[1005];
  15. int lis[1005];
  16. int res[1005];
  17. int main()
  18. {
  19. int cnt = 0;
  20. while (scanf("%d%d",&m[cnt].w,&m[cnt].s) != EOF)
  21. {
  22. m[cnt].p = cnt;
  23. cnt++;
  24. }
  25. sort(m,m+cnt,cmp);
  26. for (int i = 0;i < cnt;i++)
  27. {
  28. pre[i] = i;
  29. lis[i] = 1;
  30. }
  31. int len = 1,pos = 0;
  32. for (int i = 0;i < cnt;i++)
  33. {
  34. for (int j = 1;j < i;j++)
  35. {
  36. if (m[j].s > m[i].s && lis[j] + 1 > lis[i] && m[j].w < m[i].w)
  37. {
  38. pre[i] = j;
  39. lis[i] = lis[j] + 1;
  40. if (lis[i] > len)
  41. {
  42. len = lis[i];
  43. pos = i;
  44. }
  45. }
  46. }
  47. }
  48. int i = len - 1;
  49. while (pre[pos] != pos)
  50. {
  51. res[i--] = m[pos].p;
  52. pos = pre[pos];
  53. }
  54. res[i] = m[pos].p;
  55. printf("%d\n",len);
  56. for (int j = i;j < len;j++)
  57. printf("%d\n",res[j] + 1);
  58. return 0;
  59. }

hdu 1950 插头
题意:
2333,没有看懂,看图以及看样例(反正线不能交叉,裸的lis
思路:
nlogn的算法,因为只是求最长的长度。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int a[40005];
  4. int s[40005];
  5. int lis(int n)
  6. {
  7. int low,high,mid,top = 0;
  8. s[0] = -1;
  9. for (int i = 0;i < n;i++)
  10. {
  11. if (a[i] > s[top])
  12. s[++top] = a[i];
  13. else
  14. {
  15. low = 1,high = top;
  16. while (low <= high)
  17. {
  18. mid = (low + high) >> 1;
  19. if (a[i] > s[mid]) low = mid + 1;
  20. else high = mid - 1;
  21. }
  22. s[low] = a[i];
  23. }
  24. }
  25. return top;
  26. }
  27. int main()
  28. {
  29. int t;
  30. scanf("%d",&t);
  31. while (t--)
  32. {
  33. int n;
  34. scanf("%d",&n);
  35. for (int i = 0;i < n;i++)
  36. scanf("%d",a+i);
  37. int ans = lis(n);
  38. printf("%d\n",ans);
  39. }
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注