上链接:杭电1025
题目大意:
两条路各有n个点,每两个点连一条线,问不想交的最大个数(最长上升子序列)
贴代码(没过的!)
#include <cstdio>
#include <algorithm>
using namespace std;
struct road
{
int a, b;
}l[500001];
int state[500001];
bool cmp(road x, road y)
{
return x.a<y.a;
}
int main()
{
int n, logo=0;
while(scanf("%d", &n)!=EOF)
{
++logo;
for(int i=0; i<n; ++i)
{
scanf("%d %d", &l[i].a, &l[i].b);
state[i] = 1;
}
sort(l, l+n, cmp);
int t = 0, max = 0;
for(int i=n-1; i>=0; --i)
for(int k=i+1; k<n; ++k)
if(l[i].b<=l[k].b && state[k]+1>t)
{
state[i] = state[k]+1;
t = state[i];
break;
}
for(int i=0; i<n; ++i)
if(max < state[i])
max = state[i];
printf("Case %d:\n", logo);
if(max == 1) printf("My king, at most 1 road can be built.\n\n");
else printf("My king, at most %d roads can be built.\n\n", max);
}
return 0;
}
这个代码TLE了,然后发现了这么一个博客:
不搬运了,大意就是结合二分法降低时间复杂度
搬运一下代码,顺便加上我自己的解释:
#include <stdio.h>
int s[500001]; //存储的是dp求解的过程中上升子序列的最后一个的编号
int a[500001]; //存储的是p-1所对应的城市编号
void fun(int s[],int n,int num);
int main()
{
int i,p,r,n,len,t=0; //len为最长上升子序列的长度
while( ~scanf("%d",&n) )
{
for(i=0;i<n;i++)
{
scanf("%d %d",&p,&r);
a[p-1]=r;
}
s[0]=a[0];
len=1;
for(i=1;i<n;i++)
{
if( a[i]>s[len-1] ) s[len++]=a[i]; //如果第i个数比存储的最后一个大,将其存入s数组
else if( a[i]<s[len-1] ) fun(s,len,a[i]); //如果比最后一个小,执行fun函数
}
printf("Case %d:\n",++t);
if(len==1) printf("My king, at most %d road can be built.\n\n",len);
else printf("My king, at most %d roads can be built.\n\n",len);
}
return 0;
}
void fun(int s[],int n,int num)
{
int i=0,j=n-1;
int mid,find=0;
while(i<=j)
{
mid=(i+j)/2; //二分法
if( s[mid]==num ) { find=1;break ; } //如果中间的数与所得出的下一个数相等则退出函数
else if( s[mid]>num ) j=mid-1; //进行二分处理
else i=mid+1;
}
if(!find) s[i]=num; //找出位置后进行赋值
}
注意事项:
1.二分减少时间复杂度
2.注意输出格式road和roads不是一个= =