一、题目分析
条件一:每个城市只能建立一座桥
条件二:所有的桥与桥之间不能相交
目标:最多能建立多少座桥
步骤
-
通过排序,固定自变量的顺序
-
找因变量的最大上升子序列。(原因:找出的上升子序列越长,与下面自变量的匹配数量就越大,也就是修的桥数越多。)
总结:
-
本题还是有一些思维的难度,需要对问题进行转化。用数对描述问题比较好想,为什么要按左端点进行排序呢?似乎对于数对而言,大多数情况需要固定一个端点,比如区间合并,如果我们能想到这是一个用数对描述的问题,不妨先想一下是不是在按左端点排序一下。
-
按左端点排序后,一般的思路就是对比右端点(要不按左端点排序就没啥意义了~)。此时就是把二维的概念转化为一维的概念。本题是根据右端点的逆序关系来说明当前路线与前序的矛盾关系,我们把图画出来,现在聚焦到一维上面(就是是图的上侧),发现,如果是严格单调上升的序列,越长的话,修建的桥数越多。
-
从\(lis\)的原问题出发,思考以上方的每一个数字结尾,会产生多少座桥,也就是问题的答案。
-
思考一个复杂问题,从有一定的套路,将问题进行转化,然后再从最朴素的模板问题出发,思考问题的本质。
二、实现代码
#include <bits/stdc++.h>
using namespace std;
//线段,二维,一般用PII,因为可以不需要写cmp,直接按first排序
typedef pair<int, int> PII;
const int N = 5010;
PII a[N]; //南岸和北岸的一对友好城市的坐标
int f[N]; //记录以f[i]为结尾的一对友好城市时的,不产生交叉的最多城市对数
int n; //n组友好城市
int main() {
cin >> n;
//读入友好城市对
for (int i = 1; i <= n; i++)cin >> a[i].first >> a[i].second;
//按first排序,则南岸城市坐标由小到大
sort(a + 1, a + 1 + n);
int mx = 0;
//LIS 正向
for (int i = 1; i <= n; i++) {
f[i] = 1;
for (int j = 1; j < i; j++)
//如果南岸城市坐标由小到大,那么北岸也必须由小到大,否则就是交叉
if (a[i].second > a[j].second)
f[i] = max(f[i], f[j] + 1);
mx = max(mx, f[i]);
}
printf("%d\n", mx);
return 0;
}