【算法提高课】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)

相关推荐
倒头就睡的小比特7 小时前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!7 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼8 小时前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光9 小时前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark9 小时前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her110 小时前
并查集-听课笔记
笔记·算法·并查集
码流子10 小时前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven10 小时前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark10 小时前
从算法设计模式看编程思维的抽象能力4
算法
2601_9622186110 小时前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法