Sicily LIS |动态规划

来源:互联网 发布:怎样在淘宝买东西 编辑:程序博客网 时间:2024/06/04 17:40
  1. LIS
    Total: 103 Accepted: 43

Time Limit: 1sec Memory Limit:256MB
Description
A numeric sequence of ai is ordered if a1 <= a2 <= … <= aN. Let the subsequence of the given numeric sequence (a1, a2, …, aN) be any sequence (ai1, ai2, …, aiK), where 1 <= i1 < i2 < … < iK <= N. For example, the sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All the longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence L with the minimum aL.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10^9 each, separated by spaces. (1 <= N <= 5000)

Output
Output must contain two integers - the length of the longest ordered subsequence of the given sequence L and the minimum aL.

Sample Input
Copy sample input to clipboard
7
1 7 3 5 9 4 8
Sample Output
4 8

题意:给一个序列(a1, a2, …, aN),从中找出(ai1, ai2, …, aiK)使得 1 <= i1 < i2 < … < iK <= N并且ai1 <= ai2 <= … <= aiK。求序列(ai1, ai2, …, aiK)的最长长度以及对应的最小的aiK。这个问题就是经典的最长不下降子序列问题。
输入:第一行为整数n,随后输入n个整型数,代表序列。
输出:序列(ai1, ai2, …, aiK)的最长长度以及对应的最小的aiK

最初的思路(WA):没有理解清楚LIS的含义以及状态间的联系(以第i个字符终止的字符串的LIS是基于前面i-1个字符的LIS的基础上更新的,所以代码中应该是给定终止位置i,从0到i-1从前往后更新),这份代码却是给定i,从i+1到n-1更新,明显就把状态间的联系理解错了。

WA代码:

#include <iostream>#include <cstring>#include <iomanip>using namespace std;int main() {    int n;    cin>>n;    int num[n];    for(int i=0;i<n;i++)    {        cin>>num[i];    }    int maxLen=1,len,minAl=-1;    int max,sec_max;    for(int i=0;i<n;i++)    {        max=sec_max=num[i];        len=1;        for(int j=i+1;j<n;j++)        {            if(num[j]>max)            {                sec_max=max;                max=num[j];                len++;            }            else if(num[j]>=sec_max&&num[j]<max)            {                max=num[j];            }        }        if(len>maxLen) maxLen=len,minAl=max;    }    cout<<maxLen<<" "<<minAl<<endl;}

AC思路:以坐标i结尾的序列的LIS和其[0,i-1]“前缀”的LI有关,设f[i]保存“以i结尾的最长递增子序列”的长度,若i=0,则 f[i]=1。否则f[i]的值和其[0,i-1]前缀的最长递增子序列长度有关,用j遍历[0,i-1]得到其最长递增子序列为f[j],对每一个f[j],如果array[j]<=array[i]并且f[j]+1>f[i] (初始化为1),则f[i]的值变为f[j]+1。

即:LIS[i]=max{1,LIS[j]+1}, 其中array[i]>=array[j], j=[0,i-1]。

AC代码:

#include <iostream>using namespace std;int main() {    int n;    cin>>n;    int num[n];    for(int i=0;i<n;i++)//输入数据     {        cin>>num[i];    }    int f[n];    f[0]=1;    int maxLen=1,minAl;    for(int i=1;i<n;i++)//以第i个字符为终结点     {        f[i]=1;        for(int j=0;j<i;j++)// 更新f[i]         {            if(num[j]<=num[i]&&f[j]+1>f[i])                f[i]=f[j]+1;        }        //更新maxLen和minAl         if(f[i]>maxLen)        {            maxLen=f[i];            minAl=num[i];        }        else if(f[i]==maxLen)        {            minAl=minAl>num[i]?num[i]:minAl;        }    }    cout<<maxLen<<" "<<minAl<<endl; }/*testcase:71 3 3 2 2 2 233 2 1101 2 5 2 8 6 3 6 9 761 2 4 3 3 461 3 5 5 3 1*/
1 0