算24问题扩展

计算最小的正整数,其不能用1,2,3,4,5,6,7,8,9,10通过四则混合运算计算出来。

最终得到代码如下:

发信人: duz (duz), 信区: Science
标  题: Re: yes....1413
发信站: The unknown SPACE (Sat Apr  6 11:20:19 2002) WWW-POST

hehe , more than 600 lines:

#include <algorithm>
#include <iostream>
#include <vector>
#include <time.h>
#include <string>
#include <set>
#include <stdio.h>

#ifdef _WIN32
typedef __int64 longlong;
using namespace std;
#else
typedef long long longlong;
#endif

#ifdef _DEBUG
#include <assert.h>
#define ASSERT(x) assert(x)
#else
#define ASSERT(x)
#endif

#define MAX_NUM 10

//enlarge CACHE_LIMIT so that some expression will be saved in memory. This
will speed the program,
//but then we could not print the correct expression by expression() function.
//CACHE_LIMIT should be no more than 8. I found that the speed will drop when
CACHE_LIMIT is too large
#define CACHE_LIMIT 0

class number{
int up;
int down;
public:
number(const number& n):up(n.up),down(n.down){}
number(int n=0):up(n),down(1){}
number& operator+=(const number& n);
number& operator-=(const number& n);
number& operator*=(const number& n);
number& operator/=(const number& n);
bool is_zero()const{return down!=0&&up==0;}
bool is_valid()const{return down!=0;}
bool is_one()const{return down!=0&&up==down;}
bool operator==(const number& n)const{return
is_valid()&&n.is_valid()&&n.down*up==n.up*down;}
bool operator<(const number& n)const;
bool operator>(const number& n)const{return n<*this;}
bool operator<=(const number& n)const{return !(*this>n);}
bool operator!=(const number& n)const{return !(n==*this);}
bool operator>=(const number& n)const{return !(*this<n);}
number operator+(const number& n)const{number m(*this);return m+=n;}
number operator-(const number& n)const{number m(*this);return m-=n;}
number operator*(const number& n)const{number m(*this);return m*=n;}
number operator/(const number& n)const{number m(*this);return m/=n;}
bool is_integer()const{return down!=0&&up%down==0;}
int get_integer()const{if(is_integer())return up/down;else return -1;}
number& operator=(int n){up=n;down=1;return *this;}
int get_up()const{return up;}
int get_down()const{return down;}
};

number& number::operator +=(const number& n)
{
up=up*n.down+down*n.up;
down*=n.down;
return *this;
}

number& number::operator -=(const number& n)
{
up=up*n.down-down*n.up;
if(up<0)up=-up;
down*=n.down;
return *this;
}

number& number::operator *=(const number& n)
{
up*=n.up;
down*=n.down;
return *this;
}

number& number::operator /=(const number& n)
{
down*=n.up;
up*=n.down;
return *this;
}

bool number::operator <(const number &n)const
{
return up*n.down<n.up*down;
}

class select_iterator{
int n;//total n element;
int m;//max group id; That's group 1<<8,2<<8,...,m<<8; m should be no less
than 2.
//The select_iterator is used to split n elements into groups.
int select_array[MAX_NUM];
int sub_size[MAX_NUM];
class split_iterator{
int split_array[MAX_NUM];
int last_index;
public:
split_iterator(int size)
{
ASSERT(size<=MAX_NUM);
if(size==1)
{
last_index=0;
split_array[0]=1;
}
else
{
last_index=1;
split_array[0]=size-1;
split_array[1]=1;
}
}
bool inc()
{
int i;
ASSERT(last_index<MAX_NUM);
for(i=last_index;i>=0;--i)
{
if(split_array[i]>=2)
break;
}
if(i==-1)
{
int size=0;
for(i=0;i<=last_index;++i)
size+=split_array[i];
if(size==1)
{
last_index=0;
split_array[0]=1;
}
else
{
last_index=1;
split_array[0]=size-1;
split_array[1]=1;
}
return false;//end of search.
}
else
{
int total;
int last;
last=--split_array[i];
total=last_index-i+1;
while(total>=last){
split_array[++i]=last;
total-=last;
}
if(total>0){
split_array[++i]=total;
}
last_index=i;
}
return true;
}
friend class select_iterator;
}spliter;
void init_from_spliter();
public:
select_iterator(int size);
bool inc();
int get_sub_group_count()const{return spliter.last_index+1;}
int get_sub_size(int group_id)const{return sub_size[group_id/256-1];}
int get_group_id(int num)const{return select_array[num];}
int get_main_id(int group_id)const{return group_id/256-1;}
int get_sub_id(int group_id)const{return group_id%256;}
int split_size(int i)const{return spliter.split_array[i];}
int size()const{return n;}
#ifdef _DEBUG
void print()const;
#endif
};

select_iterator::select_iterator(int size):spliter(size)
{
init_from_spliter();
}

void select_iterator::init_from_spliter()
{
int i,prev,sg,t;
n=0,m=0;
prev=-1;
for(i=0;i<=spliter.last_index;++i)
{
if(spliter.split_array[i]!=prev)
{
sub_size[m]=spliter.split_array[i];
m++;
sg=0;
}
else
sg++;
for(t=0;t<spliter.split_array[i];t++)
{
select_array[n++]=m*256+sg;
}
prev=spliter.split_array[i];
}
}

bool select_iterator::inc()
{
int i;
int buf[MAX_NUM];
bool result;
do
{
result = next_permutation(select_array,select_array+n);
if(!result)
break;
memset(buf,-1,sizeof(buf));
for(i=0;i<n;++i){
int t=get_main_id(select_array[i]);
int q=get_sub_id(select_array[i]);
if(buf[t]<0)
buf[t]=q;
else
if(buf[t]>q)//invalid
break;
}
if(i==n)
break;
}while(true);
if(!result){
if(!spliter.inc())
{//set end.
init_from_spliter();
return false;
}
else
{
init_from_spliter();
}
}
return true;
#if 0
for(i=n-1;i>0;--i)
{
if(select_array[i]>select_array[i-1])
{
if((select_array[i]/256)==(select_array[i-1]/256))
{//if in the same group.
int j;
// if(sub_size[select_array[i]/256-1]==1)
// continue;
for(j=i-2;j>=0;--j)
{
if(select_array[j]==select_array[i-1])
break;
}
if(j>=0)//if found one.
break;
}
else
break;
}
}
if(i==0)//not found
{
if(!spliter.inc())
{//set end.
init_from_spliter();
return false;
}
else
{
init_from_spliter();
}
}
else
{
int tmp=select_array[i];
select_array[i]=select_array[i-1];
select_array[i-1]=tmp;
if(i<n-2)
{
sort(select_array+i+1,select_array+n);
}
}
return true;
#endif
return result;
}


class tree_iterator{
select_iterator spliter;
tree_iterator *next_sibling;
tree_iterator *first_child;
tree_iterator *current_child_iterator;
int get_prod;
number valued;
int data[MAX_NUM];
int pattern;
void build_tree();
void clear_child();
void set_values();
int  cached;
int  finished_cached;
set<number> caches;
set<number>::iterator caches_it;
string prod_expression()const;
string sum_expression()const;
bool no_cache_inc();
void no_cache_build_tree();
public:
bool inc();
tree_iterator(int n,int d[],int prod);
int size()const{return spliter.get_sub_group_count();}
~tree_iterator(){clear_child();}
const number& get_value()const{return valued;}
string get_pattern()const;
bool debug_sum(){return true;}
bool debug_prod(){return false;}
string expression()const{if(get_prod)return prod_expression();else return
sum_expression();}
};

string tree_iterator::prod_expression()const
{
if(first_child==NULL)
{
char buf[10];
sprintf(buf,"%d",valued.get_integer());
return string(buf);
}
else
{
int i;
string s;
bool first=true;
tree_iterator *child=first_child;
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(pattern&(1<<i)){
if(!first)
s+='*';
first=false;
s+=child->sum_expression();
}
child=child->next_sibling;
}
child=first_child;
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(!(pattern&(1<<i))){
s+='/';
s+=child->sum_expression();
}
child=child->next_sibling;
}
return s;
}
}

string tree_iterator::get_pattern()const
{
if(first_child==NULL)
{
char buf[10];
sprintf(buf,"%d",valued.get_integer());
return string(buf);
}
else
{
int i;
string s;
tree_iterator *child=first_child;
s+='[';
for(i=0;i<spliter.get_sub_group_count();++i)
{
s+=child->get_pattern();
child=child->next_sibling;
}
s+=']';
return s;
}
}

string tree_iterator::sum_expression()const
{
if(first_child==NULL)
{
char buf[10];
sprintf(buf,"%d",valued.get_integer());
return string(buf);
}
else
{
int i;
string s;
bool first=true;
tree_iterator *child=first_child;
s+='(';
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(pattern&(1<<i)){
if(!first)
s+='+';
first=false;
s+=child->prod_expression();
}
child=child->next_sibling;
}
child=first_child;
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(!(pattern&(1<<i))){
s+='-';
s+=child->prod_expression();
}
child=child->next_sibling;
}
s+=')';
return s;
}
}

bool tree_iterator::no_cache_inc()
{
if(get_prod)
pattern++;
else
pattern+=2;
if(pattern<(1<<size()))
{
set_values();
}
else
{
while(current_child_iterator&&!current_child_iterator->inc())
current_child_iterator=current_child_iterator->next_sibling;
if(current_child_iterator)
{
current_child_iterator=first_child;
pattern=1;
set_values();
}
else
{
if(spliter.inc())
{
no_cache_build_tree();
}
else
{
no_cache_build_tree();
return false;
}
}
}
return true;
}

bool tree_iterator::inc()
{
if(finished_cached)
{
++caches_it;
if(caches_it==caches.end())
{
caches_it=caches.begin();
valued=*caches_it;
return false;
}
valued=*caches_it;
return true;
}
else
{
return no_cache_inc();
}
}

void tree_iterator::clear_child()
{
tree_iterator *child=first_child;
while(child!=NULL)
{
first_child=child->next_sibling;
delete child;
child=first_child;
}
first_child=NULL;
}

tree_iterator::tree_iterator(int n,int d[MAX_NUM],int prod):spliter(n)
{
next_sibling=NULL;
first_child=NULL;
get_prod=prod;
cached=(n<=CACHE_LIMIT);
finished_cached=0;
current_child_iterator=NULL;
memcpy(data,d,sizeof(data));
build_tree();
}

void tree_iterator::set_values()
{
int i;
if(get_prod)
valued=1;
else
valued=0;
tree_iterator *child=first_child;
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(pattern&(1<<i))
{
if(get_prod)
valued*=child->valued;
else
valued+=child->valued;
}
else
{
if(get_prod)
valued/=child->valued;
else
valued-=child->valued;
}
child=child->next_sibling;
}
if(get_prod&&valued==number(0)||!valued.is_valid())
{
pattern=((1<<size())-1);
}
}

void tree_iterator::no_cache_build_tree()
{
int i;
int catche[MAX_NUM];
int prev=-1;
int m=0,sg,j,t;
clear_child();
if(size()==1)
{
valued=data[0];
pattern=1;
return;
}
for(i=0;i<spliter.get_sub_group_count();++i)
{
if(spliter.split_size(i)!=prev)
{
m++;
sg=0;
}
else
sg++;
t=m*256+sg;
int k;
for(k=0,j=0;j<spliter.size();++j)
{
if(spliter.get_group_id(j)==t){
catche[k++]=data[j];
}
}
tree_iterator *child=new tree_iterator(k,catche,!get_prod);
child->next_sibling=first_child;
first_child=child;
current_child_iterator=child;
prev=spliter.split_size(i);
}
pattern=1;
set_values();
}

void tree_iterator::build_tree()
{
if(!cached){
no_cache_build_tree();
}else{
no_cache_build_tree();
do
{
if(valued.is_valid())
caches.insert(valued);
}while(no_cache_inc());
finished_cached=1;
caches_it=caches.begin();
valued=*caches_it;
}
}

int main()
{
vector<bool> visited(10886400,false);
int a[10]={1,2,3,4,5,6,7,8,9,10};
int count=0;
int cur_scan=0;
time_t starttime=time(NULL);
{
tree_iterator it(7,a,1);
do
{
if(it.get_value().is_integer()){
int value=it.get_value().get_integer();
if(value<0)value=-value;
#ifdef _NEW_VISIT
if(!visited[value]){
cout<<value<<'='<<it.expression()<<endl;
}
#endif
visited[value]=true;
if(value==cur_scan)
{
while(cur_scan<10886400/2&&visited[cur_scan])
cur_scan++;
cout<<"Searching for "<<cur_scan<<"now"<<endl;
cout<<'/t'<<"Time cost "<<time(NULL)-starttime;
cout<<','<<"searched expression:"<<count+1<<endl;
}
}
count++;
}while(it.inc());
}
{
tree_iterator it(7,a,0);
do
{
if(it.get_value().is_integer()){
int value=it.get_value().get_integer();
if(value<0)
value=-value;
#ifdef _NEW_VISIT
if(!visited[value]){
cout<<value<<'='<<it.expression()<<endl;
}
#endif
visited[value]=true;
if(value==cur_scan)
{
while(cur_scan<10886400/2&&visited[cur_scan])
cur_scan++;
cout<<"Searching for "<<cur_scan<<"now"<<endl;
cout<<'/t'<<"Time cost "<<time(NULL)-starttime;
cout<<','<<"searched expression:"<<2*count+1<<endl;
}
}
}while(it.inc());
}
cout<<"Total expression searched:"<<count<<endl;
return 0;
}


发信人: duz (duz), 信区: Science
标  题: Re: 算24问题扩展
发信站: The unknown SPACE (Tue Apr  2 08:41:56 2002) WWW-POST

//Found a bug:
opr p[1024]; should not be defined as static:
I have modify the the program to calculate 24 for all 4 numbers,
and found the program fails to list 4599 and 4799.
After modify the static opr p[1024], the program gets correct result.

int test( int n, double x[] ) {
  static opr p[1024] ;
  static int t[1024] ;
  int i, j ;
  sort( x, x+n );
  reset_tree( n, t );
  do {
    do {
      do {
        if( fabs( eval_tree( n, t, x, p ) - target ) < 1e-6 ) {
          print_tree( n, t, x, p );
          cout << endl ;
          return 0 ;
        }
        for( j = n-2 ; j >= 0 && !p[j].next() ; j -- );
      }while( j >= 0 );
    }while( next_permutation( x, x+n ) );
  }while( next_tree( n, t ) );
  return 1 ;
}

发信人: winnt (unix), 信区: Science
标  题: Re: 赠送ID -- 建议第一步
发信站: The unknown SPACE (Thu Apr  4 19:31:49 2002), 转信

先准确计算一下复杂度. 方法是设计一个permutation算法并给出它的输出尺度.
看看谁的尺度小. 这是比较实际的方法.
也可以从理论上估计交换率下的不同表达的数目.

发信人: duz (duz), 信区: Science
标  题: Re: 还是老老实实写个程序干吧
发信站: The unknown SPACE (Thu Apr  4 19:33:57 2002) WWW-POST

我估算了一下,写一个好一点的程序,花上几天时间基本上可以穷举出来。
10个不同的数,所有不同的表达式(也就是在交换律和结合律下等价的式子看成同一个式
子)大概在50G个表达式左右。如果1秒钟可以穷举1M个式子,那么50000s就可以搞定了,
所以看来结论还是比较乐观的。
等到周末有空了,可一写一个好一点的穷举代码试一下。

 

当时fiero还使用动态规划用Java写了一个代码,可惜只是他里面的除法是用整数除法来代替了,所以解决的问题不完全相同,奇怪的是结果竟然相同。下面是他的代码:

发信人: fiero (for sale), 信区: Science
标  题: 231051
发信站: The unknown SPACE (Thu Apr  4 23:04:24 2002), 转信

haha, wrote a very stupid java program, use dynamic programming, to
calculate all values that are expressable from any subset of {1..10}
takes only several minutes.


发信人: fiero (for sale), 信区: Science
标  题: the program
发信站: The unknown SPACE (Thu Apr  4 23:09:50 2002), 转信

import java.util.*;
import java.io.*;

public class Test
{
        public static void main(String[] args)throws Exception
        {
        //x is reachable from set S::
        //   iff x equals an arithmatic expression of all numbers in S
                int[] array = getReachableSet(new int[]{1,2,3,4,5,6,7,8,9,10});
        System.out.println("array[0]=" + array[0]);
        int expected = array[0]+1;
        for(int i=1; i<array.length; i++)
        {
            if(array[i]!=expected)
            {
                System.out.println("missing: " + (expected));
                System.exit(0);
            }
            expected++;
        }
        }

    /**
     * @return all reachable numbers of set seeds.
     */
    static int[] getReachableSet(int[] seeds)throws Exception
    {
        String fileName = getFileName(seeds);
        File file = new File(fileName);
        if(file.exists())
            return loadFromFile(file);

        int[] set = calcReachableSet(seeds);
        saveToFile(file, set);
        return set;
    }

    static int indent = 0;
    static int[] calcReachableSet(int[] seeds)throws Exception
    {
        indent++;
        print(getFileName(seeds));
        long startTime = System.currentTimeMillis();
        int[] ret;
        if(seeds.length==1)
        {
            ret = seeds;
        }
        else
        {
            Splittor splitter = new Splittor(seeds);
            IntSet set = new IntSet();
            while(splitter.next()) // next permutation
            {
                // split seeds to two subsets
                int[] subA = splitter.getSubsetA();
                int[] subB = splitter.getSubsetB();
                // get reachables of the two subset
                int[] valA = getReachableSet(subA);
                int[] valB = getReachableSet(subB);
                for(int i=0; i<valA.length; i++)
                {
                    int a = valA[i];
                    for(int j=0; j<valB.length; j++)
                    {
                        int b = valB[j];
                        int min = Math.min(a,b);
                        int max = Math.max(a,b);
                        set.add(max+min);  // brutal coverage
                        set.add(max-min);
                        set.add(max*min);
                        if(min!=0)
                            set.add(max/min);
                    }
                }
            }
            ret = set.getAllAscending();
        }
        print("" + (System.currentTimeMillis() - startTime)/1000 + " sec");
        indent--;
        return ret;
    }

    static void print(String msg)
    {
        for(int i=0; i<indent*4; i++) System.out.print(" ");
        System.out.println(msg);
    }

    static int[] loadFromFile(File file)throws Exception
    {
        int[] set = new int[(int)(file.length()/4)];
        DataInputStream in = new DataInputStream(
                new BufferedInputStream(new FileInputStream(file)));
        for(int i=0; i<set.length; i++)
        {
            try{
                set[i] = in.readInt();
            }catch(Exception e){
                break;
            }
        }
        in.close();
        return set;
    }
    static void saveToFile(File file, int[] set)throws Exception
    {
        DataOutputStream out = new DataOutputStream(
                new BufferedOutputStream(new FileOutputStream(file)));
        for(int i=0; i<set.length; i++)
        {
            out.writeInt(set[i]);
        }
        out.close();
    }

    static char[] intToCharMap = new char[]
        {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',};

    static String getFileName(int[] seeds)
    {
        String name = "";
        for(int i=0; i<seeds.length; i++)
            name += intToCharMap[seeds[i]];
        return name + ".dat";
    }
}

class Splittor
{
    int[] seeds;
    int total=1;
    int bitmap = -1;
    Splittor(int[] seeds)
    {
        this.seeds = seeds;
        total <<= (seeds.length);
        total--;
    }
    boolean next()
    {
        bitmap+=2;
        return bitmap<total;
    }
    int[] getSubsetA()
    {
        return getSubset(bitmap);
    }
    int[] getSubsetB()
    {
        return getSubset(~bitmap);
    }
    int[] getSubset(int bitmap)
    {
        IntSet subset = new IntSet();
        for(int i=0; i<seeds.length; i++)
        {
            if((bitmap&(1<<i))!=0)
                subset.add(seeds[i]);
        }
        return subset.getAllAscending();
    }
}

class IntSet
{
    HashSet set = new HashSet();
    void clear()
    {
        set.clear();
    }
        void add(int x)
    {
        set.add(new Integer(x));
    }
        int[] getAllAscending()
    {
        List list = new ArrayList(set);
        Collections.sort(list);
        int total = list.size();
        int[] array = new int[total];
        for(int i=0; i<total; i++)
            array[i] = ((Integer)list.get(i)).intValue();
        return array;
    }
}

发信人: winnt (unix), 信区: Science
标  题: Re: 赠送ID
发信站: The unknown SPACE (Fri Apr  5 19:39:33 2002), 站内信件


well, you should be able to answer your question if you really did it right.
:-) At least if you have already got by hand the expressions of all the
numbers under 231051,  it would be a bound. Moreover, if you are sure about
the completeness of your permutation algorithm, the correctness of the answer
should be certain to you la.

I think it looks right. DP is definitely a right thought. I have been using
DP in my program too, but I couldn't find a good solution for memory and
efficient back-tracing. As I said in a previous post, I expect the complexity
been brought down to less than one day and eventually in 10mins. However,
your turnout does kind of surprised me early. Besides, I am still suspicious
about the total size of your files...

so i will give a little more time for my checker to break it. Or if you
are confident, just tell us you are sure and you have the answers ready. Then
I will give up the verification of this number, and prompt you a number
smaller than 231051, and hopefully you can break it timely and I will
give you the password.

again if you are sure and you (would) have the expressions for any number
below 231051, I am ready to proceed with the one number check and award
you the IDs la, unless anyone else would enlighten us otherwise in the mean
time.

发信人: fiero (for sale), 信区: Science
标  题: Re: 赠送ID
发信站: The unknown SPACE (Fri Apr  5 23:27:32 2002), 转信

the basic story is, if x is expressible by set X, y expressible by set Y,
(i.e., number x equals some arithmetic expression containing numbers in X)
then x?y is expressible for set X+Y. (? = +, -, *, /, also xy can switch order)

for any set Z, z is expressible by Z, iff exist Z1, Z2, where Z1+Z2=Z, and
Z1 Z2 not empty, no overlapping, exist z1 in Z1, z2 in Z2, that z1?z2=z.

define exp(Z)= {z | z is expressible by Z}
       X(V1, V2) = { v1?v2 | v1 in V1, v2 in V2 }

exp(Z) = sum X( exp(Z1), exp(Z2) ), for all Z1 Z2 satisfying above condition.

this approach works faster than enumerate all possible expressions, maybe
because the problem is highly degenerate. say z1 is expressible by Z1, in
N1 ways, same for z2, Z2, N2, then z1+z2 is expressible by Z1+Z2, in N1*N2
ways - but we don't care those N1*N2 ways, we don't need to run those N1*N2
ways to conclude z1+z2 is expressible. if my calculation is not wrong,
there are only 758359 numbers that are expressible by {1,2,...10}, which
shows the high degenete property.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值