AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 1012. 友好城市    原题链接    简单

作者: 作者的头像   一只野生彩色铅笔 ,  2021-06-01 15:36:22 ,  所有人可见 ,  阅读 5789


81


16

最近在补全提高课所有题目的题解,宣传一下汇总的地方提高课题解补全计划

题目描述

本题的背景是一个造桥项目,初始给定我们 $n$ 座打算建造的桥

每座桥有两个参数 $x_1$ 和 $x_2$,表示该桥一头连接在上岸坐标为$x_1$的地方,一头连在下岸坐标为$x_2$的地方

题目要求我们找出一种建桥方案,使得在所有建造的桥不相交的前提下,建造尽可能多的桥

求出该方案的造桥数量


具体的情况用文字可能不太好解释,我这里画了一张图方便大家理解

IMG_C28908166361-1.jpeg

红色虚线表示初始提供的打算建造的桥

我们要找出的方案是在不相交的前提下的最大建桥数量

也就是上面的绿线连接而成的方案

这就是本题的大致意思

题解

我们先想一下暴力怎么做

很容易想到,我们可以枚举所有的方案,然后检查方案是否合法,如果合法就考虑是否能够更新最大值答案

这么做的时间复杂度是 $O(2^n)$,而 $n$ 的数据范围是 $5000$,毫无疑问会超时。

所以,我们就需要找出一些性质进行优化

既然是要暴力枚举,我们可以考虑一个枚举方案,按照上岸的坐标从小到大来枚举

然后我们只需关心下岸的坐标之间有何关系即可

于是,可以轻易发现,上坐标从小到大枚举选择到的桥,其对应下坐标也必然是从小到大的

具体见下图:

蓝色表示该方案按照上坐标从小到大先选出来的桥

红色表示该方案的下一座桥的下坐标不是从小到大的,绿色表示是从小到大的

IMG_8E9F9D967AE9-1.jpeg

因此,该方案中,在上坐标排序的情况下,下坐标次序不是从小到大的,则必然不合法(会有相交)

于是,这题就变成了:桥以上坐标从小到大排序后,找出下坐标的最长上升子序列长度

关于如何求最长上升子序列模型的DP,大家可以看一下之前的博客,里面有详细的闫氏DP分析法

Code

我们可以用pair或者struct先把所有的桥存下来,然后按照上坐标排序

再然后,下坐标就构成了一个序列,我们只需找出该序列的最长上升子序列的长度,就求出本题的答案了

#include <iostream>
#include <algorithm>

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N = 50010;

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

int main()
{
    //input
    cin >> n;
    for (int i = 1; i <= n; ++ i) cin >> p[i].x >> p[i].y;
    //sort
    sort(p + 1, p + n + 1);
    //dp
    for (int i = 1; i <= n; ++ i)
    {
        for (int j = 0; j < i; ++ j)
        {
            if (p[j].y < p[i].y) f[i] = max(f[i], f[j] + 1);
        }
    }
    //find result
    int res = 0;
    for (int i = 1; i <= n; ++ i) res = max(res, f[i]);
    //output
    cout << res << endl;
    return 0;
}

23 评论


用户头像
Pugss_   2022-03-17 19:35      5    踩      回复

高速版

#include <iostream>
#include <cstring>
#include <algorithm>
#define f first
#define s second

using namespace std;

typedef pair<int,int> PII;
const int N = 5050;

PII a[N];
//int q[N];
int q[N];
int n;

int main()
{
    int ans = 0;
    scanf("%d",&n);
    for( int i = 0; i < n; i++ ) scanf("%d%d", &a[i].first, &a[i].second);

    int len = 0;
    q[0] = -1;

    sort(a,a + n);
    for( int i = 0; i < n; i++ )
    cout << a[i].f <<' ';

    cout << endl;

    for( int i = 0; i < n; i++ )
    cout << a[i].s <<' ';
    for( int i = 0; i < n; i++ ) 
    {
        int l = 0 , r = len;
        while( l < r )
        {
            int mid = (l + r + 1) >> 1;
            if( q[mid] < a[i].second ) l = mid;
            else r = mid - 1;
        }

        len = max( len, r + 1 );
        q[r + 1] = a[i].second;
    }

    cout << len;

    return 0;
}

用户头像
星河夜丫   2024-02-28 08:55         踩      回复

那为什么不是最长上升和下降的Max啊,只要是同方向的无交叉即可吧

用户头像
忘川_2   2025-03-24 22:05 · 天津         踩      回复

我也有可能一样的疑问,/\ 这种情况按节点排序后本身是单调的,而且按下降来说由于一一对应一样错误


用户头像
晓月兮清风   2023-02-03 15:45         踩      回复

代码出错了吧,const int N = 50010;应该是5010吧

用户头像
小笨   2023-02-10 09:14         踩      回复

N大一些也不影响答案呀

用户头像
晓月兮清风   2023-02-10 14:54    回复了 小笨 的评论         踩      回复

可更浪费空间,我开过10000010个int,ac了,但如果在工作中这样了,那可能就被薪水就被老板扣掉

用户头像
流川枫爱吃橙子吗   2023-04-04 11:06    回复了 晓月兮清风 的评论         踩      回复

..这是算法比赛,y总也说了,不要吝啬空间,只要保证不爆内存,就尽量开大点

用户头像
晓月兮清风   2023-04-05 10:18    回复了 流川枫爱吃橙子吗 的评论         踩      回复

addd

用户头像
投降赢一半   2023-06-24 03:28    回复了 晓月兮清风 的评论      1    踩      回复

你老板还能看的懂你代码? 不会换个看不懂的?

用户头像
晓月兮清风   2023-07-01 15:35    回复了 投降赢一半 的评论         踩      回复

好的嘞

用户头像
思慕雪的热带鱼   2023-08-11 09:48         踩      回复

用不到的数据空间 编译器会优化不使用

用户头像
晓月兮清风   2023-08-11 13:59    回复了 思慕雪的热带鱼 的评论         踩      回复

对,我昨天刚知道(逃


用户头像
o樱桃小完犊子o   2022-12-31 13:58         踩      回复

感觉这里排序用到了贪心,但是没有证明过程

用户头像
刘fy   2023-04-17 15:39         踩      回复

你小子名字和我对象一个微信名 第一眼还以为我对象

用户头像
o樱桃小完犊子o   2023-04-17 19:30    回复了 刘fy 的评论         踩      回复

哈哈~


用户头像
Sky390   2022-06-28 20:05         踩      回复

妙啊


用户头像
Administrator_   2022-04-03 10:43         踩      回复

顶,但还可以进一步二分优化


用户头像
wwewe   2021-12-01 11:15         踩      回复

顶


用户头像
lzyjy111   2021-10-19 09:09         踩      回复

顶一下


用户头像
acwing_9052   2021-09-14 16:38         踩      回复

妙啊


用户头像
种花家的小兔子   2021-08-22 11:30         踩      回复

铅笔巨巨 yyds


用户头像
acwing_9052   2021-07-28 19:21         踩      回复

顶


用户头像
冰糖披风侠   2021-06-02 13:44         踩      回复

# 顶一下


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息