C++旧版课程库
C++第 6 期查看课程总览

179 动态规划 - 友好城市

主要内容

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

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;
}