首页 > 代码库 > HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)

HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)

HDU 1025 Constructing Roads In JGShining‘s Kingdom(构建道路:LIS问题)

http://acm.hdu.edu.cn/showproblem.php?pid=1025

题意:

       有2n个点分布在平行的两条直线上, 上面那条是富有城市的1到n个点(从左到右分布), 下面那条是贫穷城市1到n个点(从左到右分布). 现在给出每个贫穷城市需要连接的富有城市的编号, 即(i,j)表示i贫穷城市只能连接j号富有城市 , 问你最多能构建几条贫穷城市到富有城市间的连线, 使得任意两条连线不相交(就算端点相交也不行,即不同的贫穷城市不能连接到同一个富有城市)?

分析:

       假设我们选择了第i号贫穷城市和第j号贫穷城市 (i<j) 来连接它们对应的富有城市, 只有i连接的富有城市编号<j连接的富有城市编号才不会出现相交的情况. (想想是不是)

       所以现在的问题是: 我们要对贫穷城市按1到n编号的城市选出一个最长上升子序列(序列编号是对应的富有城市的编号)即可.

 

       由于n的规模达到50W, 所以只能用O(nlogn)的算法求.

令g[i]==x表示当前遍历到的长度为i的所有最长上升子序列中的最小序列末尾值为x.(如果到目前为止,根本不存在长i的上升序列,那么x==INF无穷大)

       假设当前遍历到了第j个值即a[j], 那么先找到g[n]数组的值a[j]的下确界(即第一个>=a[j]值的g[k]k). 那么此时表明存在长度为k-1的最长上升子序列且该序列末尾的位置<j且该序列末尾值<a[j].

       那么我们可以令g[k]=a[j] 且 dp[i]=k (dp含义如解法1).

       (上面一段花时间仔细理解)

       最终我们可以找出下标最大的i使得: g[i]<INF 中i下标最大. 这个i就是LIS的长.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 1e8
using namespace std;
const int maxn=500000+5;

int n;
int a[maxn];
int g[maxn];

int main()
{
    int kase=0;
    while(scanf("%d",&n)==1)
    {
        for(int i=1;i<=n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            a[x]=y;
        }

        for(int i=1;i<=n;i++)
            g[i]=INF;

        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int k=lower_bound(g+1,g+n+1,a[i])-g;
            g[k]=a[i];
            ans=max(ans,k);
        }
        printf("Case %d:\nMy king, at most %d road%s can be built.\n\n",++kase,ans,ans==1?"":"s");
    }
    return 0;
}

HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)