线性DP----友好城市

友好城市:

题目:
Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。
北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。

输入格式
第1行,一个整数N,表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。

输出格式
仅一行,输出一个整数,表示政府所能批准的最多申请数。

输入样例:

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

输出样例:

4

问题分析:

先对数据进行录入, 那么我们可以得到一组以下关系的数据(左为南坐标, 右为北坐标):

这个时候数据展示的还不是很清晰, 我们先对两边的数据进行排序, 得到一组更加直观的数据, 即现实中城市的排列情况, 如下图:

如果你是市长, 你需要在航线不交叉的前提下, 确保使用最多的航线, 那么我们得出的航线如下(划去代表不选该航线)

说明在不交叉航线的前提下, 最多可以开辟4条航线, 那么我们是怎么实现的呢?其实是最长上升子序列长度问题, 把数据看成下图, 只对左边的坐标进行升序排序, 在交换的时候, 所对应的右边的坐标也需要进行位置交换, 因为是一一对应关系的, 左边是升序排序, 当右边有两个坐标是降序排序时, 是不是说明这里会在现实航线中出现交叉航线. 那么我们可以对右边的坐标进行求最长上升子序列长度, 如图:

 

问题转化成为求上升子序列最大长度的问题, 就变得相对简单了, 实现代码如下:

#include <iostream>
#include <string>
#include <stdlib.h>
#include <iomanip>
#include <cmath>
#include <algorithm>
using namespace std;
/*
	该问题可以先将一岸的坐标先进行排序(小到大), 
	之后再对另一岸的坐标进行查找最长升序子序列长度
	当我们发现另一岸的坐标不是升序排序, 说明有桥会交叉
*/

int main() {
	int n;
	cin >> n;
	// 数据初始化, a数组存储南岸坐标, b数组存储北岸坐标
	int a[5005], b[5005];
	for (int i = 0; i < n; i++) {
		cin >> a[i] >> b[i];
	}

	// 功能: 对南岸进行冒泡排序, 所对应的北岸友好城市也需要排序
	for (int i = 0; i < n; i++) {
		for (int j = 1; j < n - i; j++) {
			if (a[j - 1] > a[j]) {
				swap(a[j - 1], a[j]);
				swap(b[j - 1], b[j]);
			}
		}
	}

	// 功能: 计算最长升序子序列
	// d数组存储所对应的点, 升序子序列的长度
	int d[5001];
	for (int i = 0; i < n; i++) {
		d[i] = 1;
		for (int j = 0; j < i; j++) {
			if (b[j] < b[i]) {	// 找出i之前, 比i位置的坐标要小的坐标
				d[i] = max(d[i], d[j] + 1);	// 状态转移方程
			}
		}
	}

	// 功能: 求最长子序列, 即最大值
	int max_number = -1;
	for (int i = 0; i < n; i++) {
		if (d[i] > max_number) {
			max_number = d[i];
		}
	}
	cout << max_number;
	return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值