HDU 1025 Constructing Roads In JGShining's Kingdom(LIS最长上升子序列)

**题意:**2n个城市中有n个属于资源贫困型另外n个属于资源富裕型,资源贫困型的城市只缺少一种资源且缺少的资源各不相同,资源富裕的城市只产出一种资源且产出的资源也各不相同。给出了部分贫困城市的需求,需求表示了贫困城市向富裕城市进口资源,为了运送资源要在资源贫困和富裕的两城市间修路且道路不能出现交叉,问最多修多少条路?

分析:一道求最长上升子序列的题目,二维数据先将第一维从小到大排序,再找第二维数据的最长上升子序列,从而保证了所修道路之间不会交叉。需要特别注意的是结果的输出。一条路与多条路输出的结果不同。

代码:(二分查找AC)

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct node {
    int p, r;
    bool operator<(const node &a)const {
        return p < a.p;
    }
};

node TestCase[500005];
int dp[500005];

int main() {
    int n, Case = 0;
    while (scanf_s("%d", &n) != EOF) {
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &TestCase[i].p, &TestCase[i].r);
        }

        sort(TestCase, TestCase + n);

        memset(dp, 0, sizeof(dp));

        int top = 0;
        for (int i = 0; i < n; ++i) {//最长上升子序列1
            if (dp[top] < TestCase[i].r) {
                dp[++top] = TestCase[i].r;
            }
            else {
                int low = 1, high = top;
                while (low < high) {
                    int mid = (low + high) >> 1;
                    if (dp[mid] < TestCase[i].r) {
                        low = mid + 1;
                    }
                    else {
                        high = mid;
                    }
                }
                dp[high] = TestCase[i].r;
            }
        }
        if (top == 1) {
            printf("Case %d:\nMy king, at most %d road can be built.\n\n", ++Case, top);
        }
        else {
            printf("Case %d:\nMy king, at most %d roads can be built.\n\n", ++Case, top);
        }

    }
    return 0;
}
#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct node {
    int p, r;
    bool operator<(const node &a)const {
        return p < a.p;
    }
};

node TestCase[500005];
int dp[500005];

int main() {
    int n, Case = 0;
    while (scanf_s("%d", &n) != EOF) {
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &TestCase[i].p, &TestCase[i].r);
        }

        sort(TestCase, TestCase + n);

        memset(dp, 0, sizeof(dp));

        int top = 0;
        for (int i = 1; i <= n; i++)//最长上升子序列2
        {
            if (TestCase[i].r>dp[top]){//如果a[i]>栈顶部元素,则压栈  
                dp[++top] = TestCase[i].r;
            }  
            else//如果a[i]不大于栈顶部元素,则二分查找第一个比a[i]大的元素
            {
                int low = 1, high = top;
                while (low <= high)
                {
                    int mid = (low + high) >> 1;
                    if (TestCase[i].r>dp[mid])
                    {
                        low = mid + 1;
                    }
                    else
                        high = mid - 1;
                } 
                dp[low] = TestCase[i].r;//替换a[i] 
            }
        }

        if (top == 1) {
            printf("Case %d:\nMy king, at most %d road can be built.\n\n", ++Case, top);
        }
        else {
            printf("Case %d:\nMy king, at most %d roads can be built.\n\n", ++Case, top);
        }
    }
    return 0;
}

代码:(n^2超时)

#include<iostream>
#include<algorithm>
#include<cstdio>

using namespace std;

struct node {
    int p, r;
    bool operator<(const node &a)const {
        return p < a.p;
    }
};

node TestCase[500005];
int dp[500005];

int main() {
    int n, Case = 0;
    while (scanf_s("%d", &n) != EOF) {
        for (int i = 0; i < n; ++i) {
            scanf("%d%d", &TestCase[i].p, &TestCase[i].r);
        }

        sort(TestCase, TestCase + n);

        memset(dp, 0, sizeof(dp));

        for (int i = 0; i < n; ++i) {//n^2方法超时
            dp[i] = 1;
            for (int j = 0; j < i; ++j) {
                if (TestCase[i].r > TestCase[j].r) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = max(ans, dp[i]);
        }

        if (ans == 1) {
            printf("Case %d:\nMy king, at most %d road can be built.\n\n", ++Case, ans);
        }
        else {
            printf("Case %d:\nMy king, at most %d roads can be built.\n\n", ++Case, ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值