您的位置:首页 > 其它

poj-1631-Bridging signals-最长上升序列(LIS)

2017-08-14 10:55 423 查看
额(⊙o⊙)…    先放题目链接

题目传送门:https://vjudge.net/problem/POJ-1631

题目就是求最长上升序列(自己想想吧!)

lis是啥——>一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

测试数据(题目上给的太扯犊子了)

Sample Input

4
6
4 2 6 3 1 5
10
2 3 4 5 6 7 8 9 10 1
8
8 7 6 5 4 3 2 1
9
5 8 9 2 3 1 7 4 6

Sample Output

3

9

1

4


这样多好看,真是的!^_^

首先

我们来看一种方法:大致运用dp来做的

直接上代码,学过一点点dp的估计都看的懂!不懂就留言吧!

#include <algorithm>
#include <iostream>
#include <cstring>
#includ
c32c
e <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005

using namespace std;

int a
;
int dp
;

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int mmax = -1;
for(int i = 1; i <= n; i++)
{
dp[i] = 1;
for(int j = 1; j <= i; j++)
{
if(a[i] > a[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
}
mmax = max(mmax, dp[i]);
}
printf("%d\n", mmax);
}
return 0;
}


估计会有人直接去提交,我可没说是ac的代码,这是tl的代码,其实一看,就知道超时 一个for和两个for嵌套,肯定的

(・ω・`ll),复杂度为n^2

换方法吧!先上代码^_^

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005

using namespace std;

int a
;
int dp
;

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int len = 1;
dp[1] = a[1];
for(int i = 2; i <= n; i++)
{
if(a[i] > dp[len])
{
len++;
dp[len] = a[i];
continue;
}
int l = 1, r = len;

while(l <= r)
{
int mid = (l + r) / 2;

if(dp[mid] > a[i])
r = mid - 1;
else
l = mid + 1;
}

dp[l] = a[i];
}
printf("%d\n", len);
}
return 0;
}


其中对第一个代码,有个巨大的优化,这个复杂度为n*logn
首先

len = 1,dp[1] = a[1],然后对a[i]:若a[i]>dp[len],那么len++,dp[len] = a[i];

否则

我们要从d[1]到dp[len-1]中找到一个j,满足dp[j-1]<a[i]<d[j]



根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 dp[j] = a[i];

最终

答案就是len

利用dp的单调性,在查找j的时候可以二分查找,从而时间复杂度为n*logn

再看一个用stl写的

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include<vector>
#include<queue>
#include<algorithm>

using namespace std;
typedef long long LL;

const int maxn=500009;
const int INF=0x3f3f3f3f;

int n;
int a[maxn];
int dp[maxn];

int main()
{
int T;
scanf("%d", &T);

while(T--)
{
scanf("%d", &n);

for(int i=1; i<=n; i++)
scanf("%d", &a[i]);

dp[0]=0;
int len=0;

for(int i=1; i<=n; i++)
{
if(a[i]>dp[len])
{
dp[++len]=a[i];
continue;
}

int t=upper_bound(dp, dp+len, a[i])-s;
dp[t]=a[i];
}

printf("%d\n", len);
}
return 0;
}


函数具体,看大牛的博客吧!

http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html



















好吧!没有,最近在学习树状数组,忽然我……………………………………

在网上看到了,一个用来树状数组写的,还不错就打了一遍!

不解释,想看就看,不看也无关!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005
#define MAX 0x3f3f3f3f

using namespace std;

struct point
{
int num, x;
}a
;

int dp
, n;

bool comp(point  a, point b)
{
if(a.num == b.num)
return a.x < b.x;
return a.num < b.num;
}

int lowbit(int x)
{
return x & (-x);
}

int find(int x)
{
int ret = -MAX;
while(x)
{
ret = max(ret, dp[x]);
x -= lowbit(x);
}
return ret;
}

void change(int x ,int y)
{
while(x <= n)
{
dp[x] = max(dp[x], y);
x += lowbit(x);
}
}

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
memset(dp, 0, sizeof(dp));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i].num);
a[i].x = i;
}

sort(a + 1, a + n + 1, comp);

int ans = 0;
for(int i = 1; i <= n; i++)
{
int mmax = find(a[i].x);
change(a[i].x, ++mmax);
ans = max(ans, mmax);
}
printf("%d\n", ans);
}
return 0;
}


最后,推荐一个博客吧!讲了三种解决方法(写的很好,但是感觉没必要)
http://blog.csdn.net/george__yu/article/details/75896330#reply

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: