wiku30吧 关注:8贴子:232
  • 20回复贴,共1

# I'm wiku30 # 一个数学问题的OI讨论

只看楼主收藏回复

原题:不超过121的非负整数中最多能取出多少个三三不构成等差数列的数?
此题似乎有康托集的背景,猜想答案为32,取出所有三进制不带2的数即符合条件,但还没能得出证明。


来自iPhone客户端1楼2013-08-13 20:53回复
    从信息角度考虑,此题第一想法是数组+递归,又可看作”无三连续子串01串问题”@dailinsubjam 的变体,只不过剪枝条件有变化且更强--3个等距1就剪,所求值也不同--不是种数,是最多的1数


    来自iPhone客户端2楼2013-08-13 21:02
    回复
      当然还有另一个想法:排成一列的若干个数和为121,且任意连续几个数不能分为和相等的两段。 原题和2种转化从本质上是等价的,但第一种转化是标识法,而第二种利用了差分原理。第一种是转化为典型递归问题,而第二种.不知有没有可行性,但有点像动规??@二价氢


      来自iPhone客户端3楼2013-08-13 21:10
      回复
        这个数列是无序的对吧


        5楼2013-08-13 21:16
        收起回复
          时间和空间总有点纠结啊。。不过觉得这个题并不需要得出所有情况,只须得到”可能最大”的情况,那么是否有方法可以去掉明显不可能最大的情况?于是还有潜在的剪枝空间


          来自iPhone客户端6楼2013-08-13 21:20
          回复
            如果有想法可以简单说下谢了@dailinsubjam @二价氢 @ajjack999888


            来自iPhone客户端7楼2013-08-13 21:31
            回复
              我想到usaco一道等差数列的题,不过方法暴搜+剪枝


              IP属地:美国10楼2013-08-14 15:09
              收起回复
                经检验简单DFS+剪枝时间果然很长,到16 17个就不动了
                看还得简化


                11楼2013-08-14 17:43
                回复
                  最初版本程序:
                  #include "iostream"
                  using namespace std;
                  const int range=122;
                  static int st[range]={0};
                  static int maxlv=0;
                  void fill(int pl, int lv)
                  {
                  bool can1=true;
                  for(int interval=1;pl-2*interval>=0;interval++)
                  {
                  if(st[pl-interval]==1 && st[pl-2*interval]==1)
                  {
                  can1=false;
                  }
                  }
                  if(pl<range)
                  {
                  fill(pl+1, lv);
                  if(can1)
                  {
                  st[pl]=1;
                  fill(pl+1, lv+1);
                  st[pl]=0;
                  }
                  }
                  else
                  {
                  if(lv>maxlv)
                  {
                  maxlv=lv;
                  cout<<lv<<": ";
                  for(int i=0;i<range;i++)
                  {
                  if(st[i]){cout<<i<<",";}
                  }
                  cout<<endl;
                  }
                  }
                  }
                  int main()
                  {
                  st[0]=1;
                  fill(1,1);
                  cout<<maxlv;
                  cin>>maxlv;
                  return 0;
                  }


                  12楼2013-08-14 17:48
                  回复
                    于是想到递归构造。如果对于一般的n个连续的数最多只能取m(n)个,那么特别地,对于集合中的末n个数,也至多只能取m(n)个。那么对于总共N个数,已搜j个数,其中取了k个数,如果能确定k+m(N-j)对于N一定不是最大的话(比如小于之前得到的最大值),那么一定是可以剪枝的
                    不用此剪枝法,用DFS在较短时间可以搜到N=40多,但加上后同样时间可以到70多,虽然距离122还有较大的距离,但是已经有了很大的改进
                    还是得感谢数学归纳法~~吐槽一下,越来越发现离散数学和信息有点分不开了
                    再想想优化吧。。


                    14楼2013-08-15 12:56
                    回复
                      进度:已算出m(74)=22


                      16楼2013-08-15 13:31
                      收起回复
                        最后几个数的计算似乎有点跑不动。。还要优化吗?
                        就差一点了啊!


                        17楼2013-08-19 12:46
                        回复