HDUOJ 1025 - ConstructingRoadsInJGShining'sKingdom(DP:最长递增子序列LIS【nlogn算法】)

#原题

  • Problem Description

…Rich citis marked from 1 to n are located in Line I and poor ones marked from 1 to n are located in Line II.
The location of Rich City 1 is on the left of all other cities, Rich City 2 is on the left of all other cities excluding Rich City 1, Rich City 3 is on the right of Rich City 1 and Rich City 2 but on the left of all other cities … And so as the poor ones.
But as you know, two crossed roads may cause a lot of traffic accident so JGShining has established a law to forbid constructing crossed roads.
For example, the roads in Figure I are forbidden.

  • Input

Each test case will begin with a line containing an integer n(1 ≤ n ≤ 500,000). Then n lines follow. Each line contains two integers p and r which represents that Poor City p needs to import resources from Rich City r. Process to the end of file.

  • Output

For each test case, output the result in the form of sample.
You should tell JGShining what’s the maximal number of road(s) can be built.

  • Sample Input

2
1 2
2 1
3
1 2
2 3
3 1

  • Sample Output

Case 1:
My king, at most 1 road can be built.
(空行!!!)
Case 2:
My king, at most 2 roads can be built.

###解题思路:

  • 注意输出格式!!!road和roads!!!
  • 说实话这道题的题我读了好久好久,题意理解的**(好久×10000)**【网上的题意解读杂七杂八很难懂,崩溃ing】,这道题应该这么理解,才能懂应该怎么去解题:
    • 输入一个数n表示poor和rich各有n座城市
    • 每一行输入两个数字x、y,分别表示坐标为 x 的poor城市想要坐标为 y 的rich城市的资源
    • poor和rich的所有城市的坐标都是从左到右依次递增的,即两个城市的各个坐标从左到右为1,2,3,…,n
    • 然后再对应把两个相互需求的p和r城市连接起来,不能有交叉,算出最多能连几条线,即能修多少条路
    • 举个经典的例子:
      • 5
      • p:2 3 4 1 5
      • c:2 3 1 4 5
      • 如果在坐标上进行连线,很容易可以看出最多可以连3条线(22,33,55)
      • p:1 2 3 4 5
      •       | |   |
      • c:1 2 3 4 5
      • 1和4,4和1相连都会有交叉
  • 所以这个时候应该就有思路了,可以这么去解题:用一个数组a[n]来存每个p城市的坐标对应的c城市的坐标,a[i] = value : i表示p的坐标,value表示c的坐标,这样p城市的坐标就相当于已经排序好了,现在只需要求出数组a的最长递增子序列,这样肯定能保证求出来的结果不会交叉(p是排好序的,即数组a的下标),而且是最好的结果。

###代码:
####最长递增子序列优化算法:O(nlogn)

#include <stdio.h>
#include <iostream>
using namespace std;
int dp[500001], temp[500001];
int BinarySearch(int tail, int findValue)//二分查找
{
	int head = 1;
	int mid = (head + tail) / 2;
	while (mid != 1 && mid != tail)
	{
		if (dp[mid] == findValue)return mid;
		if (dp[mid] > findValue)
			tail = mid;
		else
			head = mid;
		mid = (head + tail) / 2;
		if (head + 1 == tail && dp[mid] < findValue)
			return mid + 1;
	}
	if (mid == 1 && dp[mid] > findValue)return 1;
	else return 2;
}
int main()
{
	int temp_p, temp_r, i, dpIndex;
	int n, Case = 0;
	while (scanf("%d", &n) != EOF)
	{
		Case++;
		for (i = 1; i <= n; i++)
		{
			scanf("%d%d", &temp_p, &temp_r);
			temp[temp_p] = temp_r;
		}
		dp[1] = temp[1];
		dpIndex = 1;
		for(i = 2; i <= n; i++)
		{
			if (temp[i] > dp[dpIndex])
				dp[++dpIndex] = temp[i];
			else
				dp[BinarySearch(dpIndex, temp[i])] = temp[i];
		}
		if(dpIndex == 1)
		{
			printf("Case %d:\n", Case);
			printf("My king, at most 1 road can be built.\n\n");
		}else
		{
			printf("Case %d:\n", Case);
			printf("My king, at most %d roads can be built.\n\n", dpIndex);
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值