hdoj 1025 Constructing Roads In JGShining's Kingdom ( LIS +二分法STL )

来源:互联网 发布:贪心算法的基本思想 编辑:程序博客网 时间:2024/05/22 16:53

Constructing Roads In JGShining's Kingdom

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 23135    Accepted Submission(s): 6604


Problem Description
JGShining's kingdom consists of 2n(n is no more than 500,000) small cities which are located in two parallel lines.

Half of these cities are rich in resource (we call them rich cities) while the others are short of resource (we call them poor cities). Each poor city is short of exactly one kind of resource and also each rich city is rich in exactly one kind of resource. You may assume no two poor cities are short of one same kind of resource and no two rich cities are rich in one same kind of resource.

With the development of industry, poor cities wanna import resource from rich ones. The roads existed are so small that they're unable to ensure the heavy trucks, so new roads should be built. The poor cities strongly BS each other, so are the rich ones. Poor cities don't wanna build a road with other poor ones, and rich ones also can't abide sharing an end of road with other rich ones. Because of economic benefit, any rich city will be willing to export resource to any poor one.

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.



In order to build as many roads as possible, the young and handsome king of the kingdom - JGShining needs your help, please help him. ^_^
 

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
21 22 131 22 33 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.
Hint
Huge input, scanf is recommended.
 

Author
JGShining(极光炫影)
 

题意:一个王国有富,穷城市,各为n个,一个穷城市到另一个富城市建路,一一对应,不能交叉,问最多能建多少条路

路不能交叉,每个城市都有一个序号,用LIS,两个循环超时,学习用二分法:

一个时间复杂度为O(nlogn)的算法,其算法思想为:

假设要寻找最长上升子序列的序列是a[n],然后寻找到的递增子序列放入到数组b中。

(1)当遍历到数组a的第一个元素的时候,就将这个元素放入到b数组中,以后遍历到的元素都和已经放入到b数组中的元素进行比较;

(2)如果比b数组中的每个元素都大,则将该元素插入到b数组的最后一个元素,并且b数组的长度要加1;

(3)如果比b数组中最后一个元素小,就要运用二分法进行查找,查找出第一个比该元素大的最小的元素,然后将其替换。

在这个过程中,只重复执行这两步就可以了,最后b数组的长度就是最长的上升子序列长度。例如:如该数列为:

5 9 4 1 3 7 6 7

那么:

5 //加入
5 9 //加入
4 9 //用4代替了5
1 9 //用1代替4
1 3 //用3代替9
1 3 7 //加入
1 3 6 //用6代替7
1 3 6 7 //加入

最后b中元素的个数就是最长递增子序列的大小,即4。

要注意的是最后数组里的元素并不就一定是所求的序列,

例如如果输入 2 5 1

那么最后得到的数组应该是 1 5

而实际上要求的序列是 2 5

代码:

一般二分:

#include<cstdio>#include<cstring>#include<algorithm>#define M 500000+10using namespace std;int a[M],b[M];int search(int val,int left,int right){int mid;while(left<=right){mid=(left+right)>>1;if(val>=b[mid])left=mid+1;elseright=mid-1; }return left;}int LIS(int n){int len,pos;b[1]=a[1];//a的下标是从1开始的 len=1;for(int i=2;i<=n;i++){if(a[i]>b[len])//严格递增 {len+=1;b[len]=a[i];}else{pos=search(a[i],1,len);b[pos]=a[i];}}return len;}int main(){int n,x,y;int i,j;int kcase=1;while(~scanf("%d",&n)){for(i=0;i<n;i++){scanf("%d%d",&x,&y);a[x]=y;}int ans=LIS(n);printf("Case %d:\n",kcase++);if(ans==1)//最后输出设备road 和 roads  不一样 printf("My king, at most %d road can be built.\n\n",ans); elseprintf("My king, at most %d roads can be built.\n\n",ans); }return 0; } 

STL:

#include<iostream> #include<cstdio>#include<cstring>#include<algorithm>#define M 500000+10using namespace std;int a[M],b[M];int LIS(int n){int len,pos;b[1]=a[1];//a的下标是从1开始的 len=1;for(int i=2;i<=n;i++){if(a[i]>b[len])//严格递增 {len+=1;b[len]=a[i];}else{pos=upper_bound(b+1,b+len+1,a[i])-b;//返回最后一个>= 查找值的元素的位置 b[pos]=a[i];}}return len;}int main(){int n,x,y;int i,j;int kcase=1;while(~scanf("%d",&n)){for(i=0;i<n;i++){scanf("%d%d",&x,&y);a[x]=y;}int ans=LIS(n);printf("Case %d:\n",kcase++);if(ans==1)//最后输出设备road 和 roads  不一样 printf("My king, at most %d road can be built.\n\n",ans); elseprintf("My king, at most %d roads can be built.\n\n",ans); }return 0; } 


0 0
原创粉丝点击