嘤嘤嘤,昨天两个文化课老师在上奥赛时招呼我(亲切交流),今天又要写工作报告,没时间写题解,希望今天能补上
友好城市
题目://洛谷那粘来的题面竟然能把格式粘过来
题目描述
有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航道不相交的情况下,被批准的申请尽量多。
输入格式
第1行,一个整数N,表示城市数。
第2行到第n+1行,每行两个整数,中间用一个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。
输出格式
仅一行,输出一个整数,表示政府所能批准的最多申请数。
输入输出样例
7 22 4 2 6 10 3 15 12 9 8 17 17 4 2
4
思路:
很经典的一道线型DP,跟LIS模板就一个区别,原来LIS模板中我们是只处理一串数据,这里则是把一串数据分裂成了两串,对于这种问题我们一般是找转移方程,看f[i][j]从哪个地方转移过来(例如LCS)。这道题我们可以简单的画个图,很容易可以得出一个结论:如果前一座桥的北岸坐标小于后一座桥的北岸坐标,并且前一座桥的南岸坐标小于后一座桥的南岸坐标(你要说同大于也行),那么就不会相交,可以批准,这就可以转化为求最长上升子序列的问题,而对于北岸南岸的处理,我们则可以把北岸排序,然后求出南岸的最长上升子序列
注意事项:本题数据没有严格卡最长不下降子序列,实际上本题应该求的是最长下降子序列,我们不妨简单的设想一下,如果南岸的某座城市同时被多个北岸城市连接,那么这它们的桥肯定不相交(本题是没卡,但是它的兄弟题卡了COGS 渡轮问题,当时调了半天才知道实际上应该求最长上升)
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<stack> 7 using namespace std; 8 const int maxn=1e6+5,INF=0x3f3f3f3f; 9 struct Edge{ 10 int x,y; 11 struct{};//简单的运算符重载 12 }f[maxn]; 13 int m,ans=1,low[maxn]; 14 bool cmp(Edge A,Edge B){ 15 return A.x<B.x; 16 } 17 int main(){ 18 //freopen("a.in","r",stdin); 19 scanf("%d",&m); 20 for(int i=1;i<=m;i++){ 21 cin>>f[i].x>>f[i].y; 22 } 23 sort(f+1,f+1+m,cmp); 24 low[1]=f[1].y; 25 for(int i=2;i<=m;i++){ 26 if(f[i].y>low[ans])low[++ans]=f[i].y; 27 else low[lower_bound(low+1,low+ans+1,f[i].y)-low]=f[i].y; 28 }//nlogn求LIS 29 printf("%d",ans); 30 }//嘤嘤嘤