zoukankan      html  css  js  c++  java
  • [洛谷] P1020 导弹拦截

    题目链接

    O(n²)代码:

     1 #include <stdio.h>
     2 const int MAXN = 100005;
     3 int input[MAXN];
     4 int dec[MAXN];
     5 int inc[MAXN];
     6 int cnt = 0;
     7 int ans_max = 0;
     8 int ans_need = 0;
     9 int main()
    10 {
    11     //读入 
    12     int tmp;
    13     while(scanf("%d",&tmp) != EOF)
    14     {
    15         input[cnt++] = tmp;
    16     }
    17     //初始化
    18     for(int i = 0;i < MAXN;i++)
    19     {
    20         dec[i] = 1;
    21         inc[i] = 1;
    22     }
    23     //最长下降子序列
    24     for(int i = cnt- 1;i >= 0;i--){
    25         for(int j = i + 1;j < cnt;j++){
    26             if(input[i] >= input[j]){
    27                 if(dec[i] < dec[j] + 1)
    28                 {
    29                     dec[i] = dec[j] + 1;
    30                 }
    31             }
    32         }
    33         if(dec[i] > ans_max)
    34             ans_max = dec[i];
    35     }
    36     printf("%d
    ",ans_max);
    37     
    38 
    39     //最长上升子序列
    40     for(int i = 0;i < cnt;i++){
    41         for(int j = i - 1;j >= 0;j--){
    42             if(input[i] > input[j]){
    43                 if(inc[i] < inc[j] + 1)
    44                 inc[i] = inc[j] + 1;
    45             }
    46         }
    47         if(ans_need < inc[i])
    48             ans_need = inc[i];
    49     }
    50     printf("%d",ans_need);
    51     return 0;
    52 }
    View Code

    思路:

    第一问:显然求最长不上升子序列长度即可,

    第二问:求共能组成几条最长不上升子序列

    Dilworth定理:偏序集的最少反链划分数等于最长链的长度(证明略)

    就是求最长上升子序列

    但是常规dp方法只有n²复杂度,此题只有100分(满分200)

    O(nlogn)代码

      1 #include <stdio.h>
      2 #include <algorithm>
      3 using namespace std; 
      4 const int MAXN = 1000001;
      5 int n;
      6 int m;
      7 int array[MAXN];
      8 int tree[MAXN];
      9 void build(int tree[],int array[],int node,int start,int end)
     10 {
     11     if(start == end)    {
     12         
     13         tree[node] = 0;
     14     }
     15     else{
     16     
     17         int mid = (start + end) / 2;
     18         int left_node = 2 * node + 1;
     19         int right_node = 2 * node + 2;
     20         
     21         build(tree,array,left_node,start,mid);
     22         build(tree,array,right_node,mid + 1,end);
     23         tree[node] = max(tree[left_node], tree[right_node]);
     24     }
     25     
     26 }
     27 void update(int tree[],int array[],int node,int start,int end,int idx,int val)
     28 {
     29     if(start == end){
     30         tree[node] = val;
     31         return;
     32     }
     33     else
     34     {
     35         int mid = (start + end) / 2;
     36         int left_node = 2 * node + 1;
     37         int right_node = 2 * node + 2;
     38         if(idx >= start && idx <= mid){
     39             update(tree,array,left_node,start,mid,idx,val); 
     40         }
     41         else{
     42             update(tree,array,right_node,mid + 1,end,idx,val);
     43         } 
     44         tree[node] = max(tree[left_node] ,tree[right_node]);
     45     }
     46 }
     47 int query(int array[],int tree[],int node,int start,int end,int L,int R)
     48 {
     49     if(R < start || L > end){
     50     //    printf("start:%d,end:%d L:%d R:%d
    ",start,end,L,R);
     51         return 0;
     52     }
     53     else if(start >= L && end <= R)
     54     {
     55     //    printf("start:%d,end:%d L:%d R:%d tree[%d] = %d
     return ",start,end,L,R,node,tree[node]);
     56         return tree[node];
     57     }
     58     else if(start == end){
     59     //        printf("start:%d,end:%d L:%d R:%d tree[%d] = %d
    ",start,end,L,R,node,tree[node]);
     60         return tree[node];
     61     }
     62     else{
     63     //    printf("start:%d,end:%d L:%d R:%d tree[%d] = %d
    ",start,end,L,R,node,tree[node]);
     64         int mid = (start + end) / 2;
     65         int left_node  = 2 * node + 1;
     66         int right_node = 2 * node + 2;
     67         int sum_left = query(array,tree,left_node,start,mid,L,R);
     68         int sum_right = query(array,tree,right_node,mid + 1,end,L,R);
     69         return max(sum_left, sum_right);
     70     }
     71  
     72      
     73 }
     74 int ans = 0;
     75 int cnt = 0;
     76 int max_height = 0;
     77 int main()
     78 {
     79     int tmp;
     80     while(scanf("%d",&tmp) != EOF)
     81     {
     82         array[cnt++] = tmp;
     83         if(tmp > max_height)
     84         max_height = tmp;
     85         
     86     }
     87     build(tree,array,1,1,max_height);
     88     for(int i = 0;i < cnt;i++)
     89     {
     90         int tmp = query(array,tree,1,1,max_height,array[i],max_height)+1;
     91         update(tree,array,1,1,max_height,array[i],tmp);
     92         if(tmp>ans) ans=tmp;
     93     }
     94     printf("%d
    ",ans);
     95     
     96     ans=0;
     97     build(tree,array,1,1,max_height);
     98     for(int i = 0;i < cnt;i++)
     99     {
    100         int tmp=query(array,tree,1,1,max_height,1,array[i] - 1)+1;
    101         update(tree,array,1,1,max_height,array[i],tmp);
    102         if (tmp>ans) ans=tmp;
    103     }
    104     printf("%d",ans);
    105     return 0;
    106 } 
    View Code

    思路:

    1.重点是将高度值来当作线段树下标,而不是时间序

    2.通过线段树来维护区间最长序列长度最大值

    反思:线段树处理可以将输入数据离散化,若数据为1,2,200000,则不需要建呢么打树,只需要记录相对大小1,2,3也可得到相应答案

    ,为什么可以用线段树,一知半解注意透彻理解求LIS的过程。

  • 相关阅读:
    缺省参数的注意事项
    可变和不可变类型
    Python之旅
    BBS项目 个人界面分类,文章,模板的使用详解
    Django 模板
    BBS项目 部分主界面and个人博客界面代码详解
    BBS项目 注册界面and部分首页代码详解
    BBS项目 备忘时时更新
    BBS项目 登录界面代码详解
    BBS项目 基本表关系
  • 原文地址:https://www.cnblogs.com/Ponytai1/p/12773477.html
Copyright © 2011-2022 走看看