解题报告:就是求最长上升子序列,一开始用的普通办法求的!直接TEL;就在网上找了一个时间复杂度为O(nlogn)的算法,其算法思想为:(网上找的)
假设要寻找最长上升子序列的序列是a[n],然后寻找到的递增子序列放入到数组b中。
(1)当遍历到数组a的第一个元素的时候,就将这个元素放入到b数组中,以后遍历到的元素都和已经放入到b数组中的元素进行比较;
(2)如果比b数组中的每个元素都大,则将该元素插入到b数组的最后一个元素,并且b数组的长度要加1;
(3)如果比b数组中最后一个元素小,就要运用二分法进行查找,查找出第一个比该元素大的最小的元素,然后将其替换。
在这个过程中,只重复执行这两步就可以了,最后b数组的长度就是最长的上升子序列长度。例如:如该数列为:
5 9 4 1 3 7 6 7
那么:
5 //加入
5 9 //加入
4 9 //用4代替了5
1 9 //用1代替4
1 3 //用3代替9
1 3 7 //加入
1 3 6 //用6代替7
1 3 6 7 //加入
最后b中元素的个数就是最长递增子序列的大小,即4。
要注意的是最后数组里的元素并不就一定是所求的序列,
例如如果输入 2 5 1
那么最后得到的数组应该是 1 5
而实际上要求的序列是 2 5
代码如下:
#include<stdio.h>
#define MAXN 500010
int a[MAXN],b[MAXN];
int search(int x,int l)
{
int i=1,j=l;
int index=-1;
while(i<=j)
{
index =(i+j)>>1;
if(x>b[index])
i=index+1;
if(x<b[index])
j=index-1;
}
return i;
}
int dp(int n)
{
b[1]=a[1];
int length=1;
for(int i=2;i<=n;i++)
{
if(a[i]>=b[length])
{
length++;
b[length]=a[i];
}
else
{
int index=search(a[i],length);
b[index]=a[i];
}
}
return length;
}
int main()
{
int n;
int count=0;
while(scanf("%d",&n)!=EOF)
{
int x,y;
count++;
for(int i=1;i<=n;++i)
{
scanf("%d%d",&x,&y);
a[x]=y;
}
int l=dp(n);
printf("Case %d:\n",count);
if(l==1)
{
printf("My king, at most 1 road can be built.\n");
printf("\n");
}
else
{
printf("My king, at most %d roads can be built.\n",l);
printf("\n");
}
}
return 0;
}