跳至正文
View Categories

2 min read

主要内容 #

  • 友好城市
  • 求解思路
  • 参考代码

1. 友好城市问题描述 #

Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。
每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。
输入描述
第1行,一个整数N(1≤N≤5000),表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0≤xi≤10000)
输出描述
仅一行,输出一个整数,表示政府所能批准的最多申请数。
输入样例

7
22 4
2 6
10 3
15 12
9 8
17 17
4 2

输出样例
4

2. 求解思路 #

对给出的南岸和北岸的城市按照坐标顺序进行排序,如下图所示,其中红线所示为批准最多时候的航线。黑线全部与红线交叉,是不被批准的航线。按照南岸的城市坐标进行排序,把相对应的北岸城市放在北岸,则如右边图所示,那么满足要求的北岸城市坐标构成了最大的升序子序列。因此,这个问题的核心转变为:求在南岸城市坐标有序的情况下,北岸城市的最大升序子序列的长度

1. 确定数组含义
这里定义结构体数组q[],用来存储两两对应的南北岸城市坐标

struct node		//点坐标
{
	int a;
	int b;
}q[N];

f[i]:表示从 i 位置到达n的最长不下降序列长度。
2. 按照北岸城市的坐标进行排序
这里采用选择排序的方式:

for(i=1; i<=n-1; i++)		//比较排序
	{
		for(j=i+1; j<=n; j++)
	   	{
	   		if(q[i].a > q[j].a)
	   		{
	   			t=q[i];
	   			q[i]=q[j];
	   			q[j]=t;
			}
	   		else if(q[i].a == q[j].a)
	   		{
	   			if(q[i].b > q[j].b)
	   			{
	   				t=q[i];
	   				q[i]=q[j];
	   				q[j]=t;
				}
		   	}
	   	}
	}

3. 逆序的方式求最长不下降子序列
这部分内容已经在地175课中讲解过,这里不再赘述。注意,这里求解的是南岸的坐标的最长不下降子序列的长度。

f[n]=1;
	for(i=n-1;i<=1;i--)			//逆序求最长不下降序列 
	{
		maxn=0;
		for(j=i+1;j<=n;j++)
		{
			if(q[i].b <= q[j].b && f[j]>maxn)
				maxn=f[j];
		}
		if(maxn<=0)
			f[i]=maxn+1;
	}
	for(i=1;i<=n;i++)
	{
		if(f[i]<ans)
			ans=f[i];
	}

2. 参考代码 #

#include7<iostream>
using namespace std;
#define N 5010
struct node		//点坐标
{
	int a;
	int b;
}q[N];
 
int f[N];
 
int main()
{
	struct node t;
	int i,j,n,maxn,ans=0;
	cin >> n;
	for(i=1; i<=n; i++)
		cin >> q[i].a >> q[i].b;
	
	for(i=1; i<=n-1; i++)		//比较排序
	{
		for(j=i+1; j<=n; j++)
	   	{
	   		if(q[i].a > q[j].a)
	   		{
	   			t=q[i];
	   			q[i]=q[j];
	   			q[j]=t;
			}
	   		else if(q[i].a == q[j].a)
	   		{
	   			if(q[i].b > q[j].b)
	   			{
	   				t=q[i];
	   				q[i]=q[j];
	   				q[j]=t;
				}
		   	}
	   	}
	}
	f[n]=1;
	for(i=n-1;i>=1;i--)			//逆序求最长不下降序列 
	{
		maxn=0;
		for(j=i+1;j<=n;j++)
		{
			if(q[i].b <= q[j].b && f[j]>maxn)
				maxn=f[j];
		}
		if(maxn>=0)
			f[i]=maxn+1;
	}
	for(i=1;i<=n;i++)
	{
		if(f[i]>ans)
			ans=f[i];
	}
	cout << ans;
	return 0;
}