题目描述
Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。
每对友好城市都向政府申请在河上开辟一条航线连接两个城市,但是由于河上经常起大雾,政府决定避免任意两条航线交叉,以避免事故。请编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。
输入
第1行,一个整数N(1<=N<=5000),表示城市数。
第2行到第n+1行,每行两个整数,分别表示南岸和北岸的一对友好城市的坐标。(0<=xi<=10000)
输出
一行,输出一个整数,表示政府所能批准的最多申请数。
输入样例
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
输出样例
4
思路:
原本以为很难,结果听了一下别人讲,才发现其实还算挺简单的,首先把南岸从小到大快排(北岸一起动),然后求北岸的最长上升子序列的长度。
排序完后是这样:
北岸 | 南岸 |
---|---|
2 | 6 |
4 | 2 |
9 | 8 |
10 | 3 |
15 | 12 |
17 | 17 |
22 | 4 |
求北岸的最长上升子序列的长度。
这个排序完后,用的是双重循环(洛谷上只能过一半)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct wah
{
int a,b;//a是南岸坐标,b是北岸坐标
};
wah a[100002];
int n,f[100002];//f[i]是存以i结尾的最长上升子序列的长度
void qsort(int l,int r)//不要问我为什么把快排敲上了
{
if(l>=r)return;
int k=a[(l+r)/2].a;
int i=l,j=r;
while(i<=j)
{
while(a[i].a<k)i++;
while(a[j].a>k)j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;j--;
}
}
qsort(l,j);
qsort(i,r);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].a,&a[i].b);
qsort(1,n);
int maxx=1;//maxx是最长上升子序列的长度
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=i-1;j>=1;j--)
{
if(a[j].b<a[i].b && f[j]>=f[i])f[i]=f[j]+1;//如果a[j]的值小于a[i]的值和以j结尾的长度小于以i结尾的长度,就赋为以j结尾的子序列加上a[i].b。
maxx=max(f[i],maxx);//判断最长子序列的长度
}
}
printf("%d",maxx);
return 0;
}
这个用的是二分。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
struct wah
{
int a,b;
};
wah a[100002];
int n,f[100002],t=1;
void qsort(int l,int r)
{
if(l>=r)return;
int k=a[(l+r)/2].a;
int i=l,j=r;
while(i<=j)
{
while(a[i].a<k)i++;
while(a[j].a>k)j--;
if(i<=j)
{
swap(a[i],a[j]);
i++;j--;
}
}
qsort(l,j);
qsort(i,r);
}
int midd(int m)//二分
{
int l=1,r=t,mid=(l+r)/2;
while(l<=r)
{
if(m<f[mid])r=mid-1;
else if(m>f[mid])l=mid+1;
else return mid;
mid=(l+r)/2;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].a,&a[i].b);
qsort(1,n);
f[1]=a[1].b;
for(int i=2;i<=n;i++)
{
if(f[t]<a[i].b)
{
t++;
f[t]=a[i].b;
}
else
{
f[midd(a[i].b)]=a[i].b;
}
}
printf("%d",t);
return 0;
}