友好城市

本文介绍了一个航线规划问题,涉及一组城市间的配对,并需在限制条件下最大化直连航线的数量。通过编程实现了一种解决方案,该方案考虑了航线不能交叉的约束条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description

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

Input

输入的第一行为T,表示测试示例的个数。对于每组测试数据,
第1行,一个整数N(1<=N<=5000),表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0<=xi<=10000)

Output

对于每组测试数据,仅一行,输出一个整数,表示政府所能批准的最多申请数。

Sample Input

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

Sample Output

 4

Author

HYNU 


代码:

#include<iostream>
using namespace std;
struct cs
{
    int a;
    int b;
} *x;
bool mcp(cs x1, cs x2)
{
    if(x1.a != x2.a)return x1.a < x2.a;
    else if(x1.b != x2.b)return x1.b < x2.b;
}
int main()
{
    int t, n, i, j, max;
    cin >> t;
    while(t--)
    {
        cin >> n;
        x = new cs[n];
        for(i = 0; i < n; i++)
            cin >> x[i].a >> x[i].b;
        sort(x, x + n, mcp);
        for(i = 0; i < n; i++)x[i].a = 1;
        for(i = 0; i < n; i++)
        {
            for(max = 0, j = 0; j < i; j++)
            {
                if(x[i].b > x[j].b && x[j].a > max)
                {
                    max = x[j].a;
                }
            }
            x[i].a = max + 1;
        }
        for(i = 0, max = 0; i < n; i++)
            if(max < x[i].a)max = x[i].a;
        printf("%d\n", max);
    }
}


<think>嗯,用户想找关于动态规划中的“友好城市”问题的C++解决方案。首先,我需要回忆一下友好城市问题的具体内容。这个问题应该是关于在两条河岸之间建立不交叉的桥,使得桥的数量最多。也就是给定若干对城市坐标,选择最多的不交叉的对。 然后,动态规划在这里的应用通常是基于排序后的序列,寻找最长递增子序列(LIS)。因为一旦将一边的城市排序后,另一边的城市如果按照对应的位置排列,寻找最长递增子序列就能保证不交叉。所以核心可能是将问题转化为LIS问题,再用动态规划解决。 接下来,我需要确认用户需要的是C++的实现。因此,我应该先整理思路,分步骤解释解决方法,再给出代码示例。同时,还要确保代码符合动态规划的标准结构,比如状态定义、转移方程等。 在参考用户提供的引用中,特别是引用3和引用4提到了动态规划的二维数组和状态压缩,可能相关。例如,引用3中的uniquePaths使用了二维数组来存储中间结果,而引用4提到了动态规划如何解决看似复杂的问题。不过,友好城市问题可能只需要一维的DP数组,因为转化为LIS后,DP数组通常是记录到当前位置的最长序列长度。 然后,我需要编写具体的步骤。首先,对城市坐标进行排序,然后提取另一岸的坐标数组,接着对这个数组寻找最长递增子序列的长度。这个过程的关键在于正确排序,并且正确实现LIS的DP算法。 在代码实现部分,需要注意排序的方式,比如按第一岸边坐标升序排列,当有相同坐标时,可能需要按第二岸边坐标降序排列,以防止交叉。然后,在LIS的实现中,可以使用O(n^2)的DP方法,或者更高效的O(n log n)方法,但用户可能希望看到动态规划的版本,所以选择标准的DP实现。 另外,要确保代码的正确性,比如初始化DP数组,以及状态转移方程是否正确。例如,每个元素初始化为1,然后对于每个i,遍历之前的元素j,如果对应的值更小,则更新dp[i]为max(dp[i], dp[j]+1)。 最后,要测试代码的示例输入,比如给出的样例输入,确保输出正确。同时,分析时间复杂度和可能的优化空间,比如使用二分查找优化LIS到O(n log n),但用户可能需要明确的动态规划解法,所以这里保持O(n^2)的实现。 总结步骤:问题分析、排序策略、转化为LIS、DP实现,最后给出代码和解释。同时,生成相关问题,帮助用户深入理解。</think>### 动态规划解决“友好城市”问题详解 “友好城市”问题要求在两条平行河流的南北两岸建立桥,使得桥之间互不交叉且数量最多。动态规划是解决此问题的有效方法[^4]。 #### 解决步骤 1. **排序预处理** 将城市对按北岸坐标升序排列,若北岸坐标相同则按南岸坐标降序排列,避免后续交叉判断。 2. **问题转化** 将南岸坐标序列提取出来,问题转化为求该序列的最长递增子序列(LIS)长度,保证桥不交叉[^3]。 3. **动态规划实现** 使用一维数组$dp$,其中$dp[i]$表示以第$i$个元素结尾的LIS长度: $$ dp[i] = \max(dp[j] + 1) \quad \text{其中 } 0 \leq j < i \text{ 且 } south[j] < south[i] $$ #### C++实现代码 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; struct CityPair { int north; int south; CityPair(int n, int s) : north(n), south(s) {} }; int maxBridges(vector<CityPair>& cities) { // 按北岸坐标排序,北岸相同则按南岸降序 sort(cities.begin(), cities.end(), [](const CityPair& a, const CityPair& b) { return (a.north == b.north) ? (a.south > b.south) : (a.north < b.north); }); vector<int> dp(cities.size(), 1); int max_len = 0; for (int i = 0; i < cities.size(); ++i) { for (int j = 0; j < i; ++j) { if (cities[i].south > cities[j].south) { dp[i] = max(dp[i], dp[j] + 1); } } max_len = max(max_len, dp[i]); } return max_len; } int main() { vector<CityPair> cities = {{1,2}, {2,3}, {3,1}, {4,5}, {5,4}}; cout << "最多可建桥数:" << maxBridges(cities); // 输出3 return 0; } ``` #### 算法分析 - **时间复杂度**:$O(n^2)$,主要来自双重循环的LIS计算 - **空间复杂度**:$O(n)$,使用一维DP数组 - **优化方向**:可将LIS计算优化为$O(n \log n)$的贪心+二分查找法[^4] #### 示例解析 输入城市坐标对:$$(1,2),(2,3),(3,1),(4,5),(5,4)$$ 排序后南岸序列:$$[2,3,1,5,4]$$ 最长递增子序列为$[2,3,5]$或$[2,3,4]$,长度为3。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值