最大递增和最大递减求法和方案计数比较异同分析
1 /*最大递增和最大递减的分析 2 两个其实是一个道理 3 只是维护和边界需要修改一点 4 在理解的过程中突然有个想法:那就是直接套用最大递增,只是把数列改为原来的反数列,然后边界取负无穷大,然后求 5 这个反数列的最大递增数列就可以了,事实证明,这是可行的 6 */ 7 8 /*最大递增子序列算法**/ 9 #include <iostream> 10 using namespace std; 11 int find(int *a,int len,int n)//修改后的二分查找,若返回值为x,则a[x]>=n 12 { 13 int left=0,right=len,mid=(left+right)/2; 14 while(left<=right) 15 { 16 if(n>a[mid]) left=mid+1;//维护最大 17 else if(n<a[mid]) right=mid-1; 18 else return mid; 19 mid=(left+right)/2; 20 } 21 return left; 22 } 23 int main() 24 { 25 int n,a[100],c[100],i,j,len,b[100];//新开一变量len,用来储存每次循环结束后c中已经求出值的元素的最大下标 26 while(cin>>n) 27 { 28 for(i=0;i<n;i++) 29 cin>>a[i]; 30 b[0]=1; 31 c[0]=-1;//边界 32 c[1]=a[0]; 33 len=1;//此时只有c[1]求出来,最长递增子序列的长度为1. 34 for(i=1;i<n;i++) 35 { 36 j=find(c,len,a[i]); 37 c[j]=a[i]; 38 if(j>len)//要更新len,另外补充一点:由二分查找可知j只可能比len大1 39 len=j;//更新len 40 } 41 cout<<len<<endl; 42 } 43 return 0; 44 } 45 46 /*最大递减子序列算法,都差不多*/ 47 #include <iostream> 48 using namespace std; 49 int find(int *a,int len,int n)//修改后的二分查找,若返回值为x,则a[x]>=n 50 { 51 int left=0,right=len,mid=(left+right)/2; 52 while(left<=right) 53 { 54 if(n<a[mid]) left=mid+1;//维护和递增刚好相反 55 else if(n>a[mid]) right=mid-1; 56 else return mid; 57 mid=(left+right)/2; 58 } 59 return left; 60 } 61 int main() 62 { 63 int n,a[100],c[100],i,j,len,b[100];//新开一变量len,用来储存每次循环结束后c中已经求出值的元素的最大下标 64 while(cin>>n) 65 { 66 for(i=0;i<n;i++) 67 cin>>a[i]; 68 b[0]=1; 69 c[0]=0x3f3f3f3f;//边界保证递减 70 c[1]=a[0]; 71 len=1;//此时只有c[1]求出来,最长递增子序列的长度为1. 72 for(i=1;i<n;i++) 73 { 74 j=find(c,len,a[i]); 75 c[j]=a[i]; 76 if(j>len)//要更新len,另外补充一点:由二分查找可知j只可能比len大1 77 len=j;//更新len 78 } 79 cout<<len<<endl; 80 } 81 return 0; 82 } 83 */ 84 /*最大递减计数问题*/ 85 #include<stdio.h> 86 #include<string.h> 87 #include<iostream> 88 using namespace std; 89 const int maxn=5555; 90 int a[maxn],dp[maxn],f[maxn]; 91 int main() 92 { 93 int n,i,j; 94 scanf("%d",&n); 95 for( i=1;i<=n;i++) 96 scanf("%d",&a[i]); 97 for( i=1;i<=n;i++) 98 { 99 dp[i]=1;//每个一i结尾的最下都是1 100 f[i]=1;//初始化为最大方案,有n个 101 } 102 for( i=1;i<=n;i++) 103 for( j=i+1;j<=n;j++) 104 if(a[i]>a[j]) 105 { 106 if(dp[j]<dp[i]+1)//继续增加长度 107 { 108 dp[j]=dp[i]+1; 109 f[j]=f[i];//这条路还没走完 110 } 111 else if(dp[j]==dp[i]+1)//说明到这个点有多条路 112 f[j]+=f[i]; 113 } 114 else 115 if(a[i]==a[j])//重复了,直接忽略这个点,将到这个点的方案数目置为0 116 f[j]=0; 117 // for(int i=1;i<=n;i++) 118 // printf("%d %d %d\n",i,dp[i],f[i]); 119 int max=0,answer=0; 120 for( i=1;i<=n;i++) 121 if(max<dp[i]) 122 max=dp[i]; 123 for( i=1;i<=n;i++) 124 if(max==dp[i]) 125 answer+=f[i]; 126 printf("%d %d\n",max,answer); 127 return 0; 128 } 129 130 /*最大递增计数问题 131 嗯!借用开头的结论,将原来的数列取反,然后求递减数列的方案数目*/ 132 133 /*总结:其实最大递增和最大递减就是同一个道理,相互是对方的反面*/