// unreach.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include #include #include #include #include #include #include #ifdef _WIN32 typedef __int64 longlong; #else typedef long long longlong; #endif using namespace std; #ifdef _DEBUG #include #define ASSERT(x) assert(x) #else #define ASSERT(x) #endif #define MAX_NUM 11 //#define ALL_VALUES #define SMALL_SEARCH #define SEARCH_VALUE 11 //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 8 #define MAX_BUF_SIZE 1088640000 vector visited(MAX_BUF_SIZE,false); int cur_scan=1; #if CACHE_LIMIT==0 //#define DISPLAY_NEW_VISIT //We could not define macro DISPLAY_NEW_VISIT when CACHE_LIMIT is non-zero, since we could not dump out expression when only result of sub-tree is cached (and sub-tree not available) //define CACHE_LIMIT to 0 and define DISPLAY_NEW_VISIT could dump out all the first expression to reach any integer number #endif #ifdef SMALL_SEARCH typedef int number; #define INTEGER(x) ((x)>=0?(x):-(x)) #define IS_INTEGER(x) true #define IS_VALID(x) true #else #define INTEGER(x) (x).get_integer() #define IS_INTEGER(x) (x).is_integer() #define IS_VALID(x) (x).is_valid() 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>8) and the order of the number inside the group (select_array[x]&255) int sub_size[MAX_NUM]; ///sub_size[x] provides the number of elements of all groups whose group id no more than x class split_iterator{///iterator to partition 'size' same objects into several groups (so only number of objects in each group is considered) int split_array[MAX_NUM];///number of objects in each group int last_index;///number of group - '1' public: split_iterator(int size) { ASSERT(size<=MAX_NUM); if(size==1) { last_index=0; split_array[0]=1; } else {///Usually, we need partition data into at least two groups. last_index=1; split_array[0]=size-1; split_array[1]=1; } } bool inc()///Move to the next partition { int i; ASSERT(last_index=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;tq)//invalid, all numbers in same subgroup should be ordered. Maybe we could optimize the code further break; } if(i==n) break; }while(true); if(!result){///We need increase spliter when all permutation of data are searched 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(inext_sibling to get the second child node tree_iterator *current_child_iterator;///A temporary pointer used when visiting the tree. (Maybe we should not define it here) int get_prod; ///when get_prod!=0, all topmost operators are either * or /; otherwise all topmost operators are either + or -. number valued; ///field used to save the value of the expression. int data[MAX_NUM]; ///field to save all operands used by all leaf nodes. so data[]={2,-3,1,2,5} for expression 2*(-3)/(1+2*5) int pattern; ///Used to determine whether an operator is * or / when get_prod!=0 and wheter an operator is + or - when get_prod==0. ///pattern will be treated as a bit vector. 1 for * or + and 0 for / or -. refer to function set_values(); void build_tree(); ///Function to build the tree for an expression void clear_child(); ///Function to remove all children(to clear the node) void set_values(); ///set the value of the expression according to the value of children int cached; int finished_cached; vector caches; int start_cache_id; int cur_cache_id; string prod_expression()const; ///get the expression in string format when get_prod!=0 string sum_expression()const; ///get the expression in string format when get_prod==0 bool no_cache_inc(); ///enumerate next expression void no_cache_build_tree(); ///entry function to build the tree for first expression void create_cache_file(); void read_cache_file(int offset); 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();} }; #define BUFFER_LEN 1024 number buffer[BUFFER_LEN]; string tree_iterator::prod_expression()const { if(first_child==NULL) { char buf[10]; sprintf(buf,"%d",INTEGER(valued)); return string(buf); } else { int i; string s; bool first=true; tree_iterator *child=first_child; for(i=0;isum_expression(); } child=child->next_sibling; } child=first_child; for(i=0;isum_expression(); } child=child->next_sibling; } return s; } } string tree_iterator::get_pattern()const { if(first_child==NULL) { char buf[10]; sprintf(buf,"%d",INTEGER(valued)); return string(buf); } else { int i; string s; tree_iterator *child=first_child; s+='['; for(i=0;iget_pattern(); child=child->next_sibling; } s+=']'; return s; } } string tree_iterator::sum_expression()const { if(first_child==NULL) { char buf[10]; sprintf(buf,"%d",INTEGER(valued)); return string(buf); } else { int i; string s; bool first=true; tree_iterator *child=first_child; s+='('; for(i=0;iprod_expression(); } child=child->next_sibling; } child=first_child; for(i=0;iprod_expression(); } child=child->next_sibling; } s+=')'; return s; } } bool tree_iterator::no_cache_inc() { if(get_prod) pattern++; else pattern+=2; #ifndef SMALL_SEARCH if(pattern<(1<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) { ++cur_cache_id; if(cur_cache_id>=caches.size()) { if(caches.size()==BUFFER_LEN){ read_cache_file(start_cache_id+BUFFER_LEN); if(start_cache_id<0) return false; }else{ return false; } }else{ valued=caches[cur_cache_id]; } 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)&&(n>=3); 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;ivalued; else valued+=child->valued; } else { if(get_prod) #ifdef SMALL_SEARCH valued*=child->valued; #else valued/=child->valued; #endif else valued-=child->valued; } #ifdef ALL_VALUES if(IS_INTEGER(valued)){ int x=INTEGER(valued); if(xnext_sibling; } if(get_prod&&valued==number(0)||!IS_VALID(valued)) { pattern=((1<next_sibling=first_child; first_child=child; current_child_iterator=child; prev=spliter.split_size(i); } pattern=1; set_values(); } void tree_iterator::read_cache_file(int offset) { char fName[40]; int mask=0; int i,j; for(i=0;i0){ caches.clear(); for(i=0;i ncaches; do { if(IS_VALID(valued)) ncaches.insert(valued); }while(no_cache_inc()); int size=ncaches.size(); if(size==0)return; fHandle=fopen(fName,"wb"); if(fHandle==NULL){ fprintf(stderr,"Cannot create file %s\n",fName); exit(-1); } set::iterator it; i=0,j=0; for(it=ncaches.begin();it!=ncaches.end();++it){ buffer[j]=*it; i++,j++; if(j==BUFFER_LEN){ j=0; fwrite(buffer,sizeof(number)*BUFFER_LEN,1,fHandle); } } if(j!=0){ fwrite(buffer,sizeof(number)*j,1,fHandle); } fclose(fHandle); } void tree_iterator::build_tree() { if(!cached){ no_cache_build_tree(); }else{ no_cache_build_tree(); if(size()>1){ create_cache_file(); finished_cached=1; read_cache_file(0); } } } int main() { int a[11]={1,2,3,4,5,6,7,8,9,10,11}; longlong count=0; time_t starttime=time(NULL); { tree_iterator it(SEARCH_VALUE,a,1); do { if(IS_INTEGER(it.get_value())){ int value=INTEGER(it.get_value()); if(value<0)value=-value; #ifdef DISPLAY_NEW_VISIT if(value