hdu 1025 Constructing Roads In JGShining's Kingdom

题目大意

题目挺长的,有点不容易读懂,意思就是给你2n个城市,一班为poor city,一半为rich city,每一个poor city需要对应的rich city提供相对应缺少的资源。这样一一对应,因为要建道路,并且要建足够多的道路,同时道路之间不能有相交情况。

题目分析

因为每一个poor city的编号为1~n,每一个下标对应一个rich city,需要修建足够多的道路并且道路不想交,转化一下大家会发现,就是求以poor city的编号为数组本身下标的最长递增子序列长度。需要注意的是,求最长递增子序列长度的朴素算法时间复杂度为(n*n),当n达到40000的时候就会TLE,因此这里我们需要2分查找使时间复杂度为O(n*log n)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 500005;
int a[maxn],g[maxn],dp[maxn];

int main()
{
    int n,kase = 0;
    while(scanf("%d", &n) != EOF)
    {
        int x,y;
        for(int i = 1; i <= n; i++) //因为下标必定为1~n并且不会重复,所以直接这样写就不用写结构体并且sort.
        {
            scanf("%d %d", &x, &y);
            a[x] = y;
        }
        for(int i = 1; i < maxn; i++) 
            g[i] = maxn;
        for(int i = 1; i <= n; i++)
        {
            int k = lower_bound(g+1, g+n+1, a[i]) - g; //lower_bound()用于查找大于或者等于a[i]的g数组的地址
            dp[i] = k;
            g[k] = a[i]; //更新g[k]的值
        }
        int ans = 0;  
        for(int i = 1; i <= n; i++)  //找到最长的递增子序列长度
            ans = max(ans, dp[i]);
        if(ans == 1)   //输出有坑,注意只有一条道路是,road后面不加s,并且输出之后要添加空行
            printf("Case %d:\nMy king, at most %d road can be built.\n\n", ++kase, ans);
        else
            printf("Case %d:\nMy king, at most %d roads can be built.\n\n", ++kase, ans);
    }
    return 0;
}

你可能感兴趣的:(hdu 1025 Constructing Roads In JGShining's Kingdom)