最大递增和最大递减求法和方案计数比较异同分析

  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 /*总结:其实最大递增和最大递减就是同一个道理,相互是对方的反面*/

 

posted on 2013-07-30 00:06  ok_boy  阅读(507)  评论(0编辑  收藏  举报

导航