Constructing Roads In JGShining's Kingdom
题意描述:多实例,给出想要修的道路数量,以及这条路连通的穷富城市的编号。不会有某一个城市想连通两个城市的情况,穷富城市编号都是从1开始依次编号,不允许出现交叉道路的情况,求可以修的最多道路数量。
解题思路:道路情况有很多,我们需要舍去会造成道路交叉的某道路,利用一个数组find[],它含有的元素的个数是当前上升子序列的个数(除0),也就是find数组中是递增的。当有数据不加入find数组中,要更新前面的(用二分法找),此时不会影响结果,因为find数组中值(除0以外)的个数并没增加,要使修的道路数量len 增加,有两种可能:后面有元素大于find数组的最后一个元素就有(left>len),left代表的是find数组中更新的元素位置;被另一个元素连续更新,且更新到left>len,意思就是说:选出另一元素它能比当前元素构造的上升子序列要多。
易错分析:分开写road和roads的输出情况
AC:
#include<stdio.h>
#define N 500500
int e[N],find[N];
int main(void)
{
int n,a,b,up,low,mid,len;
int k=1;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);//穷、富路
e[a]=b;//第几个与第几个路相连,赋值给它 !题中要求没有出现多对1的情况
}
find[1]=e[1];//先查到第一个可以连通了
len=1;
for(int i=2;i<=n;i++)
{
low=1;
up=len;
while(low<=up)
{
mid=(low+up)/2;
if(e[i]>find[mid])//如果第二个城市选的比第前一个城市远的话,互不影响
low=mid+1;//存进去
else
up=mid-1;//不要这条
}
find[low]=e[i];
if(low>len)
len++;
}
printf("Case %d:\n",k);
if(len==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",len);
k++;
}
return 0;
}