poj 1631 Bridging signals
来源:互联网 发布:国外的域名怎么备案 编辑:程序博客网 时间:2024/06/10 16:22
Description
A typical situation is schematically depicted in figure 1. The ports of the two functional blocks are numbered from 1 to p, from top to bottom. The signal mapping is described by a permutation of the numbers 1 to p in the form of a list of p unique numbers in the range 1 to p, in which the i:th number specifies which port on the right side should be connected to the i:th port on the left side.Two signals cross if and only if the straight lines connecting the two ports of each pair do.
Input
Output
Sample Input
4642631510234567891018876543219589231746
Sample Output
3914
Source
题意:求最长公共子序列
先介绍一种O(n*n)算法:
我们定义dp[i]: 以a[i]为末尾的最长上升子序列的长度
以a[i]结尾的上升子序列是
1 只包含a[i]的子序列
2 在满足j<i并且a[j]<a[i]的以a[j]为结尾的上升子序列末尾,追加上a[i]后得到的子序列
状态转移方程:dp[i]=max(dp[i],dp[j]+1)(当然该方程是有前提条件的)
然而由于数据过大,这样写会tle
tle 代码:
#include<iostream>using namespace std;int t;int n;int a[40000];int dp[40000];int ma;int ans;int main(){ cin>>t; while(t--) { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) dp[i]=1; ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); } ans=max(ans,dp[i]); } cout<<ans<<endl; } return 0;}
那我们要用O(logn)复杂度的算法来解决这道题
我们定义dp[i]:长度为i的上升子序列中末尾元素的最小值(不存在的话就是inf)
原理:如果子序列的长度相同,那么最末尾的元素较小的在之后会有优势。整个过程dp[i]是有序的,因此我们就可以采用二分查找来解决,那么时间复杂度就优化为nlogn。
我们举个例子来模拟一下整个过程;
假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5。n
下面一步一步试着找出它。
我们定义一个序列B,然后令 i = 1 to 9 逐个考察这个序列。
此外,我们用一个变量Len来记录现在最长算到多少了
首先,把d[1]有序地放到B里,令B[1] = 2,就是说当只有1一个数字2的时候,长度为1的LIS的最小末尾是2。这时Len=1
然后,把d[2]有序地放到B里,令B[1] = 1,就是说长度为1的LIS的最小末尾是1,d[1]=2已经没用了,很容易理解吧。这时Len=1
接着,d[3] = 5,d[3]>B[1],所以令B[1+1]=B[2]=d[3]=5,就是说长度为2的LIS的最小末尾是5,很容易理解吧。这时候B[1..2] = 1, 5,Len=2
再来,d[4] = 3,它正好加在1,5之间,放在1的位置显然不合适,因为1小于3,长度为1的LIS最小末尾应该是1,这样很容易推知,长度为2的LIS最小末尾是3,于是可以把5淘汰掉,这时候B[1..2] = 1, 3,Len = 2
继续,d[5] = 6,它在3后面,因为B[2] = 3, 而6在3后面,于是很容易可以推知B[3] = 6, 这时B[1..3] = 1, 3, 6,还是很容易理解吧? Len = 3 了噢。
第6个, d[6] = 4,你看它在3和6之间,于是我们就可以把6替换掉,得到B[3] = 4。B[1..3] = 1, 3, 4, Len继续等于3
第7个, d[7] = 8,它很大,比4大,嗯。于是B[4] = 8。Len变成4了
第8个, d[8] = 9,得到B[5] = 9,嗯。Len继续增大,到5了。
最后一个, d[9] = 7,它在B[3] = 4和B[4] = 8之间,所以我们知道,最新的B[4] =7,B[1..5] = 1, 3, 4, 7, 9,Len = 5。
于是我们知道了LIS的长度为5。
!!!!! 注意。这个1,3,4,7,9不是LIS,它只是存储的对应长度LIS的最小末尾。有了这个末尾,我们就可以一个一个地插入数据。虽然最后一个d[9] = 7更新进去对于这组数据没有什么意义,但是如果后面再出现两个数字 8 和 9,那么就可以把8更新到d[5], 9更新到d[6],得出LIS的长度为6。
那么使得dp[i]不为inf的最大的i即为最长上升子序列的长度(举例转自他人博客)
//该题要用c语言不然会超时#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#define inf 0x3f3f3fusing namespace std;int t;int n;int a[40000];int dp[40000];int main(){ scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); dp[i]=inf;//初始化为正无穷大 } for(int i=1;i<=n;i++) { *lower_bound(dp+1,dp+1+n,a[i])=a[i];//lower_bound返回一个非递减序列[first, last)中的第一个大于等于值val的位置。因此我们加上*就是该位置所储存的变量 } printf("%d\n",lower_bound(dp+1,dp+n+1,inf)-dp-1);//最后一个不为inf的数的下标即为答案 }}
最长上升子序列还有一种o(n*n)的方法是采用排序+最长公共子序列,在此就不在详述。
- POJ 1631 Bridging signals
- Bridging signals POJ 1631
- poj 1631 Bridging signals
- poj 1631 Bridging signals
- poj 1631 Bridging signals
- POJ 1631 Bridging signals
- POJ-1631-Bridging signals
- poj 1631--Bridging signals
- POJ 1631 Bridging signals
- POJ 1631 Bridging signals
- poj 1631 Bridging signals
- poj 1631 Bridging signals
- POJ - 1631 Bridging signals
- poj-1631-Bridging signals
- poj 1631 Bridging signals
- POJ 1631 Bridging signals
- poj 1631 Bridging signals
- POJ 1631 Bridging signals(LIS)
- Java基础知识的回顾之数据类型
- BigData-secondDay
- servlet开发步骤
- PAT-B] 1013. 数素数 [数论]
- json数组对象和对象数组
- poj 1631 Bridging signals
- 欧拉函数与欧拉定理
- 自我总结 --- 20170804自我总结
- 【#include<algorithm>】中包含的可以直接调用的函数
- 【LeetCode】Add Binary
- POJ3692——Kindergarten (二分图求最小顶点覆盖 (即最大匹配))
- Linux学习(九):权限与命令间的关系(极重要)
- Linux访问网站时,http://.../无法解析,出现了某些故障(-5-没有与主机名关联的地址)
- 深度增强学习前沿算法思想【DQN、A3C、UNREAL,简介】