题目描述

Palmia 河在某国从东向西流过,并把该国分为南北两个部分。河的两岸各有 N 座城市,且北岸的每一个城市都与南岸的某个城市是友好城市,而且友好关系是一一对应的。
现在要求在两个友好城市之间建立一条航线,但由于天气的原因,所有航线都不能相交,因此,就不可能给所有的友好城市建立航线。 问题:当给出城市个数和友好关系的信息之后,选择一种修建航线的方案,能建最多的航线而不相交。

输入格式

第1行:2个空格分开的整数 X X X, Y Y Y,表示Palmia河岸的长度,表示河的宽度
第2行:1个整数N (1≤N≤5000),表示在河两岸分别有多少座城市 接下来N行:每行2个空格分开的非负整数C、D(C,D ≤X),表示河两岸的一对友好城市从河最西端算起的坐标(C表示北岸的城市,D表示南岸的城市)
,在同一岸上没有两座城市的坐标相同。

输出格式

第1行: 最多能建立航线的数量K 接下来K行:每行2个用1个空格分开的整数,按北岸城市的坐标从小到大的顺序输出建立航线的K对友好城市的坐标。
若有多种方案,选择北岸城市(从后往前数起)编号大的那种方案

输入样例

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

输出样例

4
4 2
10 3
15 12
17 17

数据范围:
10 ≤ X ≤ 6000 10\leq X\leq 6000 10X6000
10 ≤ Y ≤ 100 10\leq Y\leq 100 10Y100
1 ≤ N ≤ 5000 1 \le N\le 5000 1N5000

我们可以把这个问题看成球最长公共子序列,因为公共子序列也满足原问题的性质,因为如果有航线交叉了就相当于公共子序列成了这个样子:

x y
 
y x

这个就是原问题中的航线交叉的情况,也不符合公共子序列的性质。

所以原问题就可以转换为求最长公共子序列。

但是我们可以通过一些操作把最长公共子序列转换成最长上升子序列:

我们可以把原数组经过一些转换把他转换成一个保持原顺序的最长上升子序列,然后求出来的最长上升子序列就是原问题的答案。

那么状态转移方程就是最长上升子序列的状态转移方程。
d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) dp[i]=max(dp[i], dp[j]+1) dp[i]=max(dp[i],dp[j]+1)

#include <bits/stdc++.h>
using namespace std;
#define MAXN 5005
#define INF 0x3f3f3f3f
int x, y, n;
int dp[MAXN];
bool flag[MAXN];
struct node { 
    int n, s;
    bool operator <(const node &t)const { 
        return n < t.n;
    }
};
node a[MAXN];
int main()
{ 
	cin >> x >> y >> n;
    for(int i = 1; i <= n; i++)
    	cin >> a[i].n >> a[i].s;
    sort(a + 1, a + n + 1);
    dp[1] = 1;
    int ans = 1, tmp = INF;
    for(int i = 2; i <= n; i++)
    { 
        dp[i] = 1;
        for(int j = 1; j < i; j++)
            if(a[j].s < a[i].s)
                dp[i] = max(dp[i], dp[j] + 1);
        ans = max(dp[i], ans);
    }
    cout << ans << endl;
    for(int i = n; i > 0; i--)
    { 
        if(dp[i] == ans && a[i].s < tmp)
        { 
            ans--, tmp = a[i].s;
            flag[i] = 1;
        }
    }
    for(int i = 1; i <= n; i++)
        if(flag[i])
            cout << a[i].n << " " << a[i].s << endl;
    return 0;
}

本文地址:https://blog.csdn.net/CoderZeng/article/details/109234680