最长上升子序列
题目大意:有两列城市,每列n个,一部分为rich,另一部分为poor,编号分别是自左向右为1到n,然后poor列的城市向rich出口资源,要求是每一个poor城市只能且必须向一个rich城市出口资源,出口资源需要建设道路,且道路不能有交叉,问最多建设几条道路。
在纸上画一下就会发现,我们把poor列的城市按升序排列,其对应的出口城市(rich城市)就会有一个新的序列,在这个序列中,只要rich城市编号比前一个城市的编号大,那么就可以在该城市和其对应的poor城市之间建设一条不会和前面道路相交的道路,那么就把问题转换成了最长上升子序列问题了,要注意的是本题数据量比较大,用O(n^2)算法的话会超时,改用O(nlogn)算法。
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAX 500005
using namespace std;
typedef struct A
{
int p,r;
}City;
City city[MAX];
int stack[MAX];
int cmp(const A &a,const A &b)
{
return a.p<b.p;
}
int LIS(int temp,int len)
{
int left=1,right=len;
int mid;
while(left<=right)
{
mid=(left+right)/2;
if(temp>stack[mid]) left=mid+1;
else right=mid-1;
}
return left;
}
int main()
{
int n,len,Q=0,p,r;
while(scanf("%d",&n)!=-1)
{
Q++;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&city[i].p,&city[i].r);
}
sort(city+1,city+1+n,cmp);
len=1;
stack[len]=city[1].r;
for(int i=1;i<=n;i++)
{
if(city[i].r>stack[len])
stack[++len]=city[i].r;
else
{
int j=LIS(city[i].r,len);
stack[j]=city[i].r;
}
}
if(len==1) printf("Case %d:\nMy king, at most %d road can be built.\n\n",Q,len);
else printf("Case %d:\nMy king, at most %d roads can be built.\n\n",Q,len);
}
return 0;
}
改进后的程序:
(不用创建结构体,之间用city[p]=r来表示两者之间一一对应的关系即可)
#include <cstdio>
#include <iostream>