题意:
在电路板的一侧有1 2 3 ...n n个端口 另一侧亦然 每个左侧的端口通过一条线和右边的某条端口连接起来
电路板设计时考虑不周 因此有些连线交叉 现在需要保留一些电线在电路板上(保留下来的电路板上的连线不能有交叉) 其他的采用飞线解决(焊板子的伤不起。。)
求能留在电路板上的电线的数量的最大值
思路:
将左边的端口号视为数组的index 右边与其相连的端口号视为数组里的值 则问题实质就是求该数组的最长不降子序列
求不降子序列的动态规划方法:
设有数组a[i],0<=i<=n, 如果能从i=0开始 逐渐求出以a[i]结尾的最长的不降子序列的长度,并将其存在一个数组dp[i]中
则在计算以a[i+1]结尾的最长不降子序列的长度时,可以遍历数组dp[j=0..i] 如果dp[j]+1 的值比当前dp[i+1]的值大 而且a[j]<a[i]
那么说明将a[i+1]加到以a[j]结尾的最长不降子序列之后所得到的序列 是新的最长的以a[i+1]结尾的最长不降子序列 所以此时把dp[i+1]置为dp[j]+1
这样得到的最后的数组dp[i]即代表以a[i]结尾的最长不降子序列的长度 dp[i]中的最大值即为所求a[i]的最长不降子序列的长度
时间复杂度: 需要遍历数组a[i] 对于每个a[i]又需要遍历dp[0..i-1] ~ 完成之后,需要遍历数组dp 所以O(1+2+3+..n-1)+O(n)=O(n^2) 空间复杂度O(n)
但是按这种算法提交TLE 研究了一下相关文章介绍的O(nlogn)的算法:
另外开辟一个数组array[], array[x]=y 的含义是 存在a[i]=y 而且在a中 若有1个以上的长度为x的不降子序列 则在对于所有这些子序列的最后一个数字 x是最小值
那么在考虑a[i]时 只需在array[]中查找与a[i]相等或者小于a[i]但与他最接近的元素 设为array[t]=a[k] 那么显然把a[i]接在a[k]后面,得到的就是以a[i]结尾的最长不降子序列
该子序列的长度为[t+1] 将其存入dp[i]中 并观察当前的array[t+1]与a[i]的大小关系 如果a[i]较小则用a[i]替换之(按照array的定义)
array是一个有序数组(非降 原因是:设有array[a]=b,array[c]=d,a<c,b>d, 意味着长度为c的不降子序列中 尾部数字最小的是d 则显然该序列中所有元素都不会大于d 那么这些元素都小于b 在这些元素(一共c个 包括d)中选出a个 组成新的子序列 则该序列是以一个有a个元素 并以一个小于b的元素结尾的不降子序列, which, 根据array[a]=b是不可能的)
由于array非降 则在array中查找可以使用二分查找 时间复杂度降为O(nlogn) AC~
代码:
1 // 1631.cpp : Defines the entry point for the console application. 2 //This code is A MESS! 3 4 #include "stdio.h" 5 6 unsigned int biSearch(int data[],unsigned int length,int num) 7 { 8 int left=0,right=length,mid=(left+right)/2; 9 while(left<=right) 10 { 11 if(num>data[mid]) left=mid+1; 12 else if(num<data[mid]) right=mid-1; 13 else return mid; 14 mid=(left+right)/2; 15 } 16 return right; 17 18 } 19 20 unsigned int solve(unsigned int data[],int length) //find the length of Longest Increasing Sublist 21 { 22 unsigned int i; 23 int j; 24 unsigned int ans=0; 25 unsigned int temp[40005]; 26 int temp2[40005]; 27 28 for(i=0;i<length;i++){ 29 temp[i]=1; 30 temp2[i]=40006; 31 } 32 temp2[0]=-1; 33 temp2[1]=data[0]; 34 35 36 for(i=1;i<length;i++) 37 { 38 j=biSearch(temp2,i,data[i]); 39 temp[i]=j+1; 40 if(data[i]<temp2[j+1]) 41 temp2[j+1]=data[i]; 42 } 43 44 45 46 for(i=0;i<length;i++) 47 if(ans<temp[i]) ans=temp[i]; 48 return ans; 49 } 50 51 52 53 int main(void) 54 { 55 unsigned int scenarios; 56 unsigned int ports,portCount; 57 unsigned int sceCount=0; 58 unsigned int data[40005]; 59 60 61 scanf("%d",&scenarios); 62 while(scenarios!=0) 63 { 64 scanf("%d",&ports); 65 for(portCount=0;portCount<ports;portCount++) 66 scanf("%d",&data[portCount]); //deposit data of one scenario in array data 67 printf("%d",solve(data,ports)); 68 scenarios--; 69 } 70 71 return 0; 72 }