【算法提高课】AcWing1012.友好城市 长期攻克提高课-day8(8/219)

题目的描述

1、朴素版题意描述

背景设定

Palmia 国东西走向的大河分南北两岸,两岸各分布 N 个坐标互不重复的城市;北岸每个城市唯一对应南岸一个友好城市,配对关系两两不重复。每一对友好城市申请修建一条跨河直线航道,要求获批的航道任意两条都不能交叉,需要挑选尽可能多的航道通过审批,求最多可批准的航道条数。

输入规则

  1. 首行输入整数 N,代表城市总对数;
  2. 后续 N 行,每行输入两个整数,依次为一组友好城市里南岸坐标、北岸坐标。

任务要求

输出满足航道互不交叉前提下,最多能批准的申请数量。

2、数学描述

1. 符号定义

设共有N组友好城市配对,构造配对集合:

T={(si,ni), i=1,2,...,N}T=\{(s_i,n_i),\ i=1,2,\dots,N\}T={(si,ni), i=1,2,...,N}

  • sis_isi:第i组配对的南岸城市横坐标,所有sis_isi取值互异;
  • nin_ini:第i组配对的北岸城市横坐标,所有nin_ini取值互异; 配对映射si↦nis_i \mapsto n_isi↦ni为一一映射。

2. 约束条件

选取子集T′⊆TT'\subseteq TT′⊆T,对T′T'T′内任意两组不同配对(sa,na),(sb,nb)(s_a,n_a),(s_b,n_b)(sa,na),(sb,nb),二者连接而成的线段(航道)无交点。

3. 优化目标

最大化子集T′T'T′包含的元素个数∣T′∣|T'|∣T′∣,输出该最大数值。

3、数据范围

1≤N≤5000,1≤N≤5000,1≤N≤5000,

0≤xi≤100000≤x_i≤100000≤xi≤10000

题目的分析

我们先上结论,再上证明。

1、结论

  1. 输入N组坐标:每组依次给出南岸城市横坐标、北岸友好城市横坐标;
  2. 先按南岸城市坐标从小到大 给所有配对排序;
  3. 排序后提取对应北岸城市的坐标序列,问题等价于 找这个序列里最长上升子序列的长度:
    • 南岸坐标递增排布时,北岸坐标也单调递增,航道就不会交叉;北岸坐标递减则航道交叉;
  4. 最长上升子序列的长度就是最多可批准的航道数量。

2、证明

大河水平延伸,南岸在下、北岸在上,横坐标从左到右增大(越靠右 x 坐标越大):

  • 南岸点记S、北岸点记N,一对友好城市连线段SN就是航道;
  • 取两组航道:航道 1(Sa,Na)(S_a,N_a)(Sa,Na)、航道 2(Sb,Nb)(S_b,N_b)(Sb,Nb),强制约束SaS_aSa在南岸左侧、SbS_bSb在南岸右侧,即sa<sb\boldsymbol{s_a < s_b}sa<sb(南岸横坐标严格左小右大),只分两种北岸位置情况画图对比。

情况1:sa<sbs_a<s_bsa<sb且na<nbn_a<n_bna<nb(北岸左小右大)

南岸靠左的城市连北岸靠左城市,南岸靠右的城市连北岸靠右城市,线段走向一致,不会相交。

情况2:sa<sbs_a<s_bsa<sb且na>nbn_a>n_bna>nb(北岸左大右小)

南岸靠左的点连北岸靠右的点、南岸靠右的点连北岸靠左的点,线段必然相交。

严格逻辑证明(结合图形结论)

步骤 1:排序固定南岸顺序

把所有配对按南岸横坐标升序重排,得到固定顺序:

s1<s2<s3<⋯<sNs_1<s_2<s_3<\dots<s_Ns1<s2<s3<⋯<sN 此时只需观察对应北岸序列 A={n1,n2,...,nN}A=\{n_1,n_2,\dots,n_N\}A={n1,n2,...,nN}的大小关系。

步骤 2:多选航道的无交叉约束

若同时选中下标i<ji<ji<j的两条航道,天然满足si<sjs_i<s_jsi<sj; 由图形结论:想要航道不交叉,必须强制ni<njn_i<n_jni<nj。 推广到多条航道:选中一批下标i1<i2<⋯<iki_1<i_2<\dots<i_ki1<i2<⋯<ik,全部两两无交叉  ⟺  \iff⟺

ni1<ni2<⋯<nikn_{i_1}<n_{i_2}<\dots<n_{i_k}ni1<ni2<⋯<nik 这恰好就是上升子序列的定义。

步骤 3:最大值等价结论

题目要求选中航道数量最多,等价于找满足下标递增、数值递增的最长子序列,即序列A的最长上升子序列 (LIS) 长度。

3、闫氏DP分析法

我们可以从上方的结论得到,这道题本质还是最长上升子序列,只不过要固定南岸的自变量,即:把所有城市配对按南岸坐标sis_isi从小到大排序 ,南岸坐标成为严格递增的自变量,顺序完全锁定,不会变动;此时每组配对唯一对应一个北岸坐标nin_ini,得到一维序列{n1,n2,...,nN}\{n_1,n_2,\dots,n_N\}{n1,n2,...,nN}。

所以,我们就把这道题转换成求"自变量"固定后的"因变量"的最长上升子序列。

首先根据经验,这种题一般只有一维状态。

我们可以设:dpidpidpi

集合:所有朝同一方向且以nin_ini结尾的上升子序列的集合

属性:Max

即:所有朝同一方向且以nin_ini结尾的上升子序列的长度集合的最大值

然后状态计算,开始划分集合,我们以最后一个集合dpi来划分

显然集合可以划分为从{dp0,dp1,dp2,...,dpi−1}\{dp0,dp1,dp2,...,dpi-1\}{dp0,dp1,dp2,...,dpi−1}到达dpidpidpi的所有长度(要满足:nj<ni,j∈{j∣0≤j<i}n_j<n_i,j∈\{j|0≤j<i\}nj<ni,j∈{j∣0≤j<i}),因为dpidpidpi的定义是以nin_ini结尾的最长上升子序列的长度,因此dpi=max({dp0,dp1,dp2,...,dpi−1})+1,(nj<ni,j∈{j∣0≤j<i})dpi=max(\{dp0,dp1,dp2,...,dpi-1\})+1,(n_j<n_i,j∈\{j|0≤j<i\})dpi=max({dp0,dp1,dp2,...,dpi−1})+1,(nj<ni,j∈{j∣0≤j<i}),即:dpi=max⁡{dpj+1∣0≤j<i, nj<ni}dpi = \max\big\{dpj + 1 \mid 0 \le j < i,\ n_j < n_i\big\}dpi=max{dpj+1∣0≤j<i, nj<ni},这也是我们本次动态规划的状态转移方程。

即:dpi=max⁡{dpj+1∣0≤j<i, nj<ni}dpi = \max\big\{dpj + 1 \mid 0 \le j < i,\ n_j < n_i\big\}dpi=max{dpj+1∣0≤j<i, nj<ni}

闫氏DP分析图

题目的代码

**题目地址:**https://www.acwing.com/problem/content/1014/

cpp 复制代码
#include <iostream>
#include <algorithm>

using namespace std;

typedef pair<int, int> PII;

const int N = 5010;

int n;
PII city[N];
int f[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) 
        scanf("%d%d", &city[i].first, &city[i].second);
    // 最重要的一步排序,按照pair自带排序规则,先排first,若first相等再排second
    sort(city, city + n);

    int res = 0;
    for (int i = 0; i < n; i ++ )
    {
        f[i] = 1;
        for (int j = 0; j < i; j ++ )
            // 根据"因变量"找到最长上升子序列的长度
            if (city[i].second > city[j].second)
                f[i] = max(f[i], f[j] + 1);
        res = max(res, f[i]);
    }
    // 输出最多能批准的申请数量
    printf("%d\n", res);

    return 0;
}

时间复杂度: O(n2)O(n^2)O(n2)

空间复杂度: O(n)O(n)O(n)

相关推荐
longlongzihan15 分钟前
LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
算法·leetcode·链表
residual_fan16 分钟前
基于控制感知域对抗网络的变工况故障诊断:从控制系统与运行状态协同的角度建立模型
人工智能·算法·数据挖掘·数据分析
翻山越岭的少年22 分钟前
用控制信号理解状态变化:基于控制感知域对抗网络的变工况故障诊断
算法
longlongzihan32 分钟前
从LeetCode 19. 删除链表的倒数第 N 个结点深入理解“哨兵节点”
c++·算法·leetcode·链表
DeroZan39 分钟前
# jieba 分词 & 文本语料分析 & Python 内置函数笔记
算法
Gigavision44 分钟前
CAS(ME)²数据集 感知图卷积网络算法 CAS(ME)²数据集下载
网络·算法
杜 硕1 小时前
快速排序02
算法·排序算法
careathers1 小时前
【数据结构】二叉树拓展
数据结构·算法
java_nnnn1 小时前
LeetCode刷题滑动窗口(长度最小的子数组)
算法·leetcode·职场和发展
@atweiwei1 小时前
训练 AI 大模型系列之 LoRA:不动模型本体,靠一条低秩旁路改专长(附完整手算算例)
人工智能·算法·ai·语言模型·rag