您的位置:首页 > 编程语言 > C语言/C++

最长上升子序列(HDU 1423,PKU 1887,ZJU1986)(c++) 可输出序列

2010-07-15 02:00 417 查看
最长上升子序列(HDU 1423, PKU 1887,ZJU1986)
假如序列为3 2 8 6 7 4 5 7 3,求最大上升子序列:
传说中O(n^2)算法,一般人能想到(DP)
for (i=0;i<n;i++)
{
max=0;
for (j=0;j<i;j++)
if ((a[i]>=a[j]) &&(max<d[j]))max=d[j];
d[i]=max+1;
if (fmax<d[i]) fmax=d[i];
}
printf("%d",fmax);
传说中O(n*logn)算法,节约时间空间……
(二分查找和贪心)
数组实现:
const int N = 40001;
int a
, D
, n;
void DP ( )
{
scanf("%d", &n);
int i, len = 0;
for ( i = 0; i < n; i++ )
scanf("%d", &a[i]);
memset(D, 0, sizeof(D));
int m, l, r;
for ( i = 0; i < n; i++ )
if ( a[i] > D[len] )
D[++len] = a[i];
else
{
l = 0, r = len;
while ( l < r - 1 )
{
m = (l + r) / 2;
if ( a[i] >D[m] )
l = m;
else
r = m;
}
if ( a[i] < D[l] )
D[l] = a[i];
else
D[r] = a[i];
}
printf("%d/n", len);
}
(需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列,用堆栈实现的原理相同,但用堆来优化的话还没搞懂最后怎样把序列输出来)

那如果要输出序列呢?
是不是单单用数组D呢?
不是的,以3 2 8 6 7 4 5 7 3为例,D数组是2 3 5 7,这显然不对,因为在计算中我们只是取单组最大的值来保存长度,所以,要输出序列就要在中间保存一下:
#define MAX 40005
inta[MAX],b[MAX],p,n,D[MAX],Left,Right,mid,blen,num;
void DP()
{
blen = 0;
int i;
scanf("%d",&p);
for (i = 1;i <= p;i++)
cin>>numbers[i];
int ans = b[1];
for (i = 1;i <= p;i++)
{
num =a[i];
Left = 1;
Right = blen;
while (Right >= Left)
{
mid = (Left + Right)/2;
if (D[mid] >= num)
Right = mid - 1;
else
Left = mid + 1;
}
b[i] = Left;
D[Left] = num;
if (Left > blen) //check if the blen should plus one itself
blen = Left;
if (ans < b[i])
ans = b[i];
}
printf("%d/n",ans);
}
这里的的D[]就保存了每个结尾的最大子序列长度
b : 01 12 2 3 2342
a : 03 2 8 6 7 4 5 7 3
用b从后往前就可以看到最大上升子序列了

(欢迎大家指正 资料参考部分模板 )
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: