HDU 1025 Constructing Roads In JGShining's Kingdom 动态规划 + 二分

题目大意:

本质上就是对于贫穷城市p需要匹配富裕城市r, 用a[p]  = r表示之后不难发现就是求数列a[ i ]的最长不降子序列

由于不会出现两个贫穷城市匹配同一个富裕城市故相当于求最长上升子列

如果用传统的O(n^2)的方法求将会超时

这里用dp[ i ]表示长度为 i 的子列的结尾最小是dp[ i ] 那么,显然dp[ i ] 满足单调递增

初始化dp[1] = a[1]

考虑没下一个数 a[ i ], 对于当前找到的最长长度len, 从dp[1 到 len ] 中找到a[ i ] 可以放的位置,如果a[ i ] > dp[len] 那么len++; dp[len] = a[ i ];

否则对于 dp[ ii ] < a[ i ] < dp[ ii + 1 ] 更新dp[ ii + 1 ] 为 a[ i ]即可这样一直持续到 a[n],由于每次二分查找dp[1 ~ len]中对应的位置, 时间复杂度为O(n*logn)

代码如下:

Result  :  Accepted     Memory  :  560 KB     Time  :  140 ms

/*
 * Author: Gatevin
 * Created Time:  2014/8/9 19:26:09
 * File Name: hehe.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 500000

int a[maxn + 10];
int dp[maxn + 10];
int n;
int len, mid;

int main()
{
    int cnt = 0;
    while(~scanf("%d", &n))
    {
        cnt++;
        int ta,tb;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d %d", &ta, &tb);
            a[ta] = tb;
        }
        dp[1] = a[1];
        len = 1;
        int l,r,mid;
        for(int i = 2; i <= n; i++)
        {
            l = 1;
            r = len;
            while(l <= r)
            {
                mid = (l + r) / 2;
                if(dp[mid] < a[i])
                {
                    l = mid + 1;
                }
                else
                {
                    r = mid - 1;
                }
            }
            dp[l] = a[i];
            if(l > len) len = l;
        }
        printf("Case %d:\n", cnt);
        printf("My king, at most %d %s can be built.\n\n", len, len == 1 ? "road" : "roads");
    }   
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值