题目链接:Click here
题意:这道题目看了好几遍,英语是硬伤啊~~
借助了谷歌翻译~~自己修改了一下,毕竟电脑翻译的真不忍直视啊
JGShining的王国包括2n个小城市,分别位于两条平行线。
这些城市中有一半都含有丰富的资源(我们称他们丰富的城市),而另一些缺少资源(我们称他们为穷人市)。每个贫困城市缺少一种资源,每一个富有城市富有一种资源。你可以假设没有任何两个城市同时缺少一个同类型的资源,并没有两个城市富含一个同类型的资源。
随着工业的发展,贫困城市想从那些富有城市购买资源。存在的道路很小小,他们无法保证重型卡车通过,所以要建设新的道路。贫穷的城市强烈BS对方,富有的也是。贫穷的城市不想建立与其他穷国的道路,富有的城市也无法忍受与其他富国共享道路的尽头。
由于经济利益的,任何丰富的城市会愿意出口资源对任何一个贫穷城市。标志着从1到n丰富黎平位于I线和穷国标志着从1到n位于二号线。富城1的位置是在所有其他城市的左边,富城2是所有其他城市不包括丰富的城市1的左边,富城3是富城1和富城2的权利,但在左边所有其他城市的...等为穷国。
但你也知道,两个交叉的道路可能会造成大量交通事故,所以JGShining已经建立了一个法律,禁止修建道路交叉。
为了建造更多的路,王国的年轻英俊的国王 - JGShining需要你的帮助,请帮他。 ^ _ ^
思路:看了一些解题报告,说是关于最长上升子序列的问题,但我感觉虽然有些关系,其实主要的还是贪心吧,个人意见。
参考了网上很多代码,现在借用一个大神的思路和数据做下解释:
假设要寻找序列是a[n]
(1)当遍历到数组a的第一个元素的时候,就将这个元素放入到dp数组中,以后遍历到的元素都和已经放入到dp数组中的元素进行比较;
(2)如果比dp数组中的每个元素都大,则将该元素插入到dp数组的最后一个元素,并且dp数组的长度要加1;
(3)如果比b数组中最后一个元素小,就要运用二分法进行查找,查找出第一个比该元素大的最小的元素,然后将其替换。
假设上面是富有城市a,下面是贫困城市b。
第一步:
a1与b5之间建设道路
a2与b9之间建设道路
第二步:
因为与a3相连的城市号比a1与a2的都要小,所以a1与b5 a2与b9之间断开。只留下a3与b4
此时dp[2]还是9,这个参照程序就知道为什么
第三步,第四步:
a4与b1,a5与b3,a7与b6,a8与b7
看图应该能够理解吧~~
这时,答案就是dp的下标,4
具体看代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cstdlib>
using namespace std;
int dp[500003], city[500003];
int main()
{
int n, cout, a, b, ans, left, right, mid;
cout= 1;
while(scanf("%d", &n) != EOF)
{
ans = 1;
for(int i = 0; i < n; i++)
{
scanf("%d%d", &a, &b);
city[a] = b; //富有城市要建立连接的贫穷城市的标号
}
dp[1] = city[1];
for(int i = 2; i <= n; i++)
{
left = 0;
right = ans;
while(left <= right)
{//二分法查找
mid = (left + right) / 2;
if(city[i] > dp[mid])
left = mid + 1;
else
right = mid - 1;
}
dp[left] = city[i]; //替换该标号
if(left > ans) //如果找不到,证明标号比dp中所有的都大,则插到数组末尾
ans++;
}
printf("Case %d:\n", cout);
if(ans == 1)//注意道路的单复数问题
printf("My king, at most 1 road can be built.\n\n");
else
printf("My king, at most %d roads can be built.\n\n", ans);
cout++;
}
return 0;
}