轮船问题(ship.pas)
【问题描述】
某国家被一条河划分为南北两部分,在南岸和北岸总共有N对城市,每一城市在对岸都有唯一的友好城市,任何两个城市都没有相同的友好城市。每一对友好城市都希望有一条航线来往,于是他们向政府提出了申请。由于河终年有雾。政府决定允许开通的航线就互不交叉(如果两条航线交叉,将有很大机会撞船)。兴建哪些航线以使在安全条件下有最多航线可以被开通。
【输入格式】
输入文件(ship.in):包括了若干组数据,每组数据格式如下:
【输出格式】
输出文件(ship.out):要在连续的若干行里给出每一组数据在安全条件下能够开通的最大航线数目。
【输入输出样例】
Ship.in 30 5 4 2 5 1 3 | Ship.out 3 |
维护一个一位数组d,并且这个数组是动态扩展的,初始大小为1,d[i]表示最长上升自序列长度是i的所有子串中末尾最小的数,根据这个数字,我们可以知道只要当前考察这个数比d[i]大,那么当前这个数一定能通过d[i]构成一个长度为i+1的上升子序列,当然我们希望在d数组中找到一个尽量靠后的数字,这样我们得到的上升子串的长度最长,查找的时候使用二分搜索,这样时间复杂度下降了
#include <iostream>
using namespace std;
//D[k] = min{A[i]} (F[i] = k)
int d[500001],a[500001];
int Binary_Search(int ai,int len)
{
int _left=1,_right=len,mid;
while(_left<_right)
{
mid=(_left+_right)/2;
if(ai > d[mid])
_left=mid+1;
else
_right=mid-1;
}
return _left;
}
int LIS_Length(int n)
{
d[1]=a[1];
int len=1;
for(int i=2;i<=n;i++)
{
if(a[i] < d[1])
d[1]=a[i];
else if(a[i] > d[len])
{
len++;
d[len]=a[i];
}
else
{
int j=Binary_Search(a[i],len);
if(a[i] > d[j]) //如果d[j]<a[i],那d[j+1]一定大于a[i]
d[j+1]=a[i];
else
d[j]=a[i];
}
}
return len;
}
int main()
{
int n,x,y,len,num=0;
while(cin>>n)
{
num++;
for(int i=1;i<=n;i++)
{
cin>>x>>y;
a[x]=y;
}
len=LIS_Length(n);
cout<<"Case "<<num<<":"<<endl;
cout<<"My king, at most "<<len<<" road";
if(len > 1)
cout<<'s';
cout<<" can be built."<<endl;
cout<<endl;
}
return 0;
}