首页 > 代码库 > HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)
HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)
HDU 1025 Constructing Roads In JGShining‘s Kingdom(构建道路:LIS问题)
http://acm.hdu.edu.cn/showproblem.php?pid=1025
题意:
有2n个点分布在平行的两条直线上, 上面那条是富有城市的1到n个点(从左到右分布), 下面那条是贫穷城市1到n个点(从左到右分布). 现在给出每个贫穷城市需要连接的富有城市的编号, 即(i,j)表示i贫穷城市只能连接j号富有城市 , 问你最多能构建几条贫穷城市到富有城市间的连线, 使得任意两条连线不相交(就算端点相交也不行,即不同的贫穷城市不能连接到同一个富有城市)?
分析:
假设我们选择了第i号贫穷城市和第j号贫穷城市 (且i<j) 来连接它们对应的富有城市, 只有i连接的富有城市编号<j连接的富有城市编号才不会出现相交的情况. (想想是不是)
所以现在的问题是: 我们要对贫穷城市按1到n编号的城市选出一个最长上升子序列(序列编号是对应的富有城市的编号)即可.
由于n的规模达到50W, 所以只能用O(nlogn)的算法求.
令g[i]==x表示当前遍历到的长度为i的所有最长上升子序列中的最小序列末尾值为x.(如果到目前为止,根本不存在长i的上升序列,那么x==INF无穷大)
假设当前遍历到了第j个值即a[j], 那么先找到g[n]数组的值a[j]的下确界(即第一个>=a[j]值的g[k]的k值). 那么此时表明存在长度为k-1的最长上升子序列且该序列末尾的位置<j且该序列末尾值<a[j].
那么我们可以令g[k]=a[j] 且 dp[i]=k (dp含义如解法1).
(上面一段花时间仔细理解)
最终我们可以找出下标最大的i使得: g[i]<INF 中i下标最大. 这个i就是LIS的长.
AC代码:
#include<cstdio> #include<cstring> #include<algorithm> #define INF 1e8 using namespace std; const int maxn=500000+5; int n; int a[maxn]; int g[maxn]; int main() { int kase=0; while(scanf("%d",&n)==1) { for(int i=1;i<=n;i++) { int x,y; scanf("%d%d",&x,&y); a[x]=y; } for(int i=1;i<=n;i++) g[i]=INF; int ans=0; for(int i=1;i<=n;i++) { int k=lower_bound(g+1,g+n+1,a[i])-g; g[k]=a[i]; ans=max(ans,k); } printf("Case %d:\nMy king, at most %d road%s can be built.\n\n",++kase,ans,ans==1?"":"s"); } return 0; }
HDU 1025 Constructing Roads In JGShining's Kingdom(构建道路:LIS问题)