<html>

<head><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- MyFirstUnitAd -->
<ins class="adsbygoogle"
     style="display:inline-block;width:970px;height:250px"
     data-ad-client="ca-pub-5778386704669218"
     data-ad-slot="1503492166"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>

<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Population</title>
</head>

<body>



<p align="left"><font size="6" color="#FF0000"><b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
String Searching</b></font></p>

<div align="left">
  <pre><b><font color="#ff0000" size="5">A.<span lang="en-ca"> </span>First Edition</font></b></pre>
</div>
<div align="left">
  <pre><b>This is second<span lang="en-ca"> edition of </span>code competition problem 1 which I try to use my DFSArray class to solve. So, it is </b></pre>
</div>
<div align="left">
  <pre><b>also an improved edition of my DFS class. (How many editions have been made for DFS? I don't remember.)</b></pre>
</div>
<div align="left">
  <pre><b><font color="#ff0000" size="5"><span lang="en-ca">B</span>.<span lang="en-ca"><a name="problem"></a>The problem</span></font></b></pre>
</div>
<div align="left">
  <b><a href="CodingProb1.htm">Code Competition Problem 1.</a></b></div>
<div align="left">
  ””</div>
<div align="left">
  ””</div>
<div align="left">
  <b><font color="#ff0000" size="5"><span lang="en-ca">C</span>.<span lang="en-ca">The
  </span></font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>idea of 
  program</b></font></span></div>
<div align="left">
  <pre><b>It is the same old trick--To setup a series of options and at each node test these options. However, I thought</b></pre>
</div>
<div align="left">
  <pre><b>I run into unsolvable obstacles at first. You see, &quot;abcdab&quot;, for example, there are two &quot;ab&quot; at different postion.</b></pre>
</div>
<div align="left">
  <pre><b>Then it means for option &quot;ab&quot;, there exists two result! But my &quot;validateOptions&quot; function only return true or false.</b></pre>
</div>
<div align="left">
  <pre><b>How can I recognize there are actually TWO different results derived from same option---&quot;ab&quot;? It seems a contradictive</b></pre>
</div>
<div align="left">
  <pre><b>to TURING Machine---for one input there should be one definite output. However, there is a way to solve it! Because</b></pre>
</div>
<div align="left">
  <pre><b>there is different state inside class. See the pointer is at different positions of string, so, it means a different</b></pre>
</div>
<div align="left">
  <pre><b>states can be tracked. I add an internal data member--state to indicate the position of pointer in string. When </b></pre>
</div>
<div align="left">
  <pre><b>the positions are different, we must traverse all choices again.</b></pre>
</div>
<div align="left">
  <pre><b><font size="5" color="#FF0000">D.<span lang="en-ca"><a name="Method"></a>The </span>major functions</font></b></pre>
</div>
<div align="left">
  <pre><b>1. void StrSearching::trackString()</b></pre>
</div>
<div align="left">
  <pre><b>This is quite like the old &quot;backTrack&quot; function and save &quot;curString&quot; instead of &quot;choices&quot; in an array.</b></pre>
</div>
<div align="left">
  <pre><b>2. bool StrSearching::validateOption(int sonData)</b></pre>
</div>
<div align="left">
  <pre><b>First you should make sure there is an matching choice, then try to make sure there is no repeating result in</b></pre>
</div>
<div align="left">
  <pre><b>upper nodes. (Note that different choices may lead to same result, but we only care about results instead of</b></pre>
</div>
<div align="left">
  <pre><b>&quot;choices&quot; here.£©</b></pre>
</div>
<div align="left">
  <pre><b>£³£®void StrSearching::readFile(const char* fileName)</b></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>This function read rules into a 2-dimension array, and initial string and target string also at end of this array.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>4. bool DFS::beginCount(int max, bool findall)</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>This function was changed a little bit to fix the logic loophole: I should always evaluate first for any node</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>before trying to generate new nodes from it. And whenever a node touch down, it should return to try next node.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>5. char* StrSearching::replaceStr(char* source, char* target, int start, int size)</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>A utility function to insert a target string into source with starting position at start and replaced string length</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><b>is size. Do you understand? Surely it is easy to read code.</b></span></pre>
</div>
<div align="left">
  <pre><span lang="en-ca"><font size="5" color="#FF0000"><b>E</b></font></span><b><font color="#ff0000" size="5">.</font></b><span lang="en-ca"><font size="5" color="#FF0000"><b>Further improvement</b></font></span></pre>
</div>
<div align="left">
  <pre><b>1.<span lang="en-ca"> The change in</span></b><span lang="en-ca"><b> this version of DFS is considered to be a rather big one. Should I standardize it as lib? I doubt it.</b></span></pre>
</div>
<pre>””</pre>
<pre><b><font color="#FF0000" size="3">//file DFS.h</font></b></pre>
<pre>#ifndef DFS_H
#define DFS_H
#include &lt;iostream&gt;

using namespace std;

const int MaxSonCount=8;

const int MaxLevel = 120;

const int MaxOptions = 16;

const int MaxNodeCount = 300;

class DFS
{
private:
	void initialize(DFS* now);
	static bool initialized;
	static DFS* nodeList[MaxNodeCount];
	static bool findAll;
	static int optionArray[MaxOptions];
	static int optionCount;
	static char** nameString;
	static int solutionCount;
	static int maxLevel;
	void addSon(int sonData);
	bool touchDown();
	void setMaxLevel(int max) { maxLevel = max;}
	DFS* upDate();
	static int domino;
	bool hasBrother();
	DFS* nextBrother();
	bool generate();
	DFS* findNext();
	void putNode(int theIndex) { nodeList[theIndex] = this;}
protected:
	int state;
	int stateCount;
	int parent;
	int sonCount;
	int sonIndex;
	int son;
	int depth;
	int index;//index in nodeList
	int data;
	static int trackRecord[MaxLevel];
	void backTrack();
	DFS* getNode(int theIndex){return nodeList[theIndex];}
	DFS* getParent(){return getNode(parent);}
	bool hasParent(){return parent!=-1;}
	virtual void setStateCount();
	virtual void onAfterAdded();
	virtual void onGenerate();
	virtual void onBeginSearch();
	virtual DFS* createSon() = 0;
	virtual bool validateOption(int sonData) =0;	//made it pure virtual
	virtual void onLeave();
	virtual bool evaluate() = 0;
	virtual void collectResult();
public:
	int getSolutionCount(){ return solutionCount;}
	void setOptions(int* array, int size);
	void setNameStr(char** str){nameString = str;}
	bool beginCount(int max, bool findall=false);
	virtual ~DFS();//virtual destructor
};

#endif</pre>
<pre>””</pre>
<pre><b><font color="#FF0000" size="3">//file DFS.cpp
</font></b>
#include &lt;iostream&gt;
#include &quot;DFS.h&quot;

using namespace std;

int DFS::domino = 0;
bool DFS::findAll = false;
bool DFS::initialized = false;
int DFS::maxLevel = 0;
int DFS::optionArray[MaxOptions] = {0};
char** DFS::nameString=NULL;
int DFS::solutionCount = 0;
int DFS::optionCount = 0;
DFS* DFS::nodeList[MaxNodeCount] = {NULL};
int DFS::trackRecord[MaxLevel]= {0};


bool DFS::touchDown()
{
	return depth==maxLevel;
}

void DFS::onBeginSearch()
{
	//programmer may need do some initializing job here!
}

//user can synchronize sonNode and fatherNode
void DFS::onAfterAdded()
{
	//programmer may need do something for his own purpose
}

void DFS::onLeave()
{
	DFS* ptr =this;
	if (ptr-&gt;hasParent())
	{
		DFS* father = ptr-&gt;getParent();
		domino -= father-&gt;sonCount;
		father-&gt;sonCount = 0;
		father-&gt;son = -1;	
	}	
}

void DFS::backTrack()
{
	DFS* ptr = this;

	while (ptr-&gt;hasParent())
	{
		trackRecord[ptr-&gt;depth-1] = ptr-&gt;data;
		ptr = ptr-&gt;getParent();
	}
}


//a stack
void DFS::collectResult()
{
	backTrack();
	cout&lt;&lt;&quot;The route is:\n&quot;;
	for (int i=0; i&lt;depth; i++)
	{
		cout&lt;&lt;nameString[trackRecord[i]]&lt;&lt;&quot;, &quot;;
	}
	cout&lt;&lt;&quot;\nIt is number:&quot;&lt;&lt;solutionCount++;
	cout&lt;&lt;endl;
}

void DFS::setOptions(int *array, int size)
{
	optionCount = size;
	for (int i=0; i&lt;size; i++)
	{
		optionArray[i] = *(array+i);
	}
}


DFS::~DFS()
{
	if (initialized)
	{
		for (int i=1; i&lt;MaxNodeCount; i++)//the i=0 is root which is not dynamic allocated!
		{
			delete nodeList[i];
		}
		domino =0;
		initialized=false;
	}
}


void DFS::onGenerate()
{
	//programmer may need to initialize at this stage
}


bool DFS::beginCount(int max, bool findall)
{
	DFS* ptr = this;
	setMaxLevel(max);
	findAll = findall; //setup if want all result
	initialize(this);
	onBeginSearch();//this is done from root!

	while (ptr!=NULL)
	{
		if (ptr-&gt;evaluate())
		{
			ptr-&gt;collectResult();
			if (!findAll)
			{
				break;
			}
			else
			{
				ptr = ptr-&gt;findNext();
								
			}
		}
		if (ptr-&gt;touchDown())//for a new son
		{
			ptr=ptr-&gt;findNext();
								
		}
		//programmer may need to initialize at this stage
		ptr-&gt;onGenerate();
		if (ptr-&gt;generate())
		{
			ptr = ptr-&gt;upDate();//move to first son			
		}
		else
		{
			ptr = ptr-&gt;findNext();//for a new son
			
		}
	}
	if (solutionCount==0)
	{
		cout&lt;&lt;&quot;no solution!&quot;;
		return false;
	}
	else
	{
		cout&lt;&lt;&quot;Total solution is &quot;&lt;&lt;solutionCount&lt;&lt;endl;
		return true;
	}
		
}
	
DFS* DFS::findNext()
{
	DFS* ptr = this;
	DFS* dummy;
	while (ptr!=NULL)
	{
		if (ptr-&gt;hasBrother())
		{
			ptr = getNode(ptr-&gt;index+1);//next brother
			
			return ptr;			
		}
		else
		{
			if (ptr-&gt;hasParent())
			{
				dummy = ptr;
				ptr = ptr-&gt;getParent(); //if 
				dummy-&gt;onLeave(); //only clear when go up one level
			}
			else
			{
				break;
			}
		}
	}
	return NULL;
}
void DFS::setStateCount()
{
	//user should specify here what kind of internal state number it is.
}

bool DFS::generate()
{
	bool result = false;

	if (touchDown())
	{
		return false;
	}
	stateCount =1;	
	setStateCount();

	for (state =0; state&lt;stateCount; state++)
	{
		//this is preorder and I don't bother to 
		//give choices for midorder or postorder
		for (int i=0; i&lt; optionCount; i++)
		{
			if (validateOption(optionArray[i]))
			{
				addSon(optionArray[i]);
				result = true;		
			}
		}
	}
	return result;
}


DFS* DFS::upDate()
{
	//return first son	
	return getNode(son);
}



void DFS::addSon(int sonData)
{	
	if (sonCount+1&lt;MaxSonCount)
	{
		if (domino==MaxNodeCount)
		{
			cout&lt;&lt;&quot;Exceeds limit of node list&quot;&lt;&lt;endl;
			return;
		}
		//DFS* ptr = createSon();
		DFS* ptr = nodeList[domino];
		ptr-&gt;index = domino;//
		//ptr-&gt;putNode(domino);		

		if (sonCount==0)//if it is the first son
		{
			son = domino;//first son 
		}
		domino++;
		ptr-&gt;state = state;
		ptr-&gt;stateCount = stateCount;
		ptr-&gt;data = sonData;
		ptr-&gt;sonCount = 0;
		ptr-&gt;son = -1;//temporarily
		ptr-&gt;parent = index;
		ptr-&gt;depth = depth+1;
		ptr-&gt;sonIndex = sonCount;
		sonCount++;
		ptr-&gt;onAfterAdded();
	}
	else
	{
		cout&lt;&lt;&quot;Exceed max of sons!&quot;;
	}
}

void DFS::initialize(DFS* now)
{
	now-&gt;index =0;	
	now-&gt;depth = 0;
	now-&gt;sonCount = 0;
	now-&gt;sonIndex = -1;
	now-&gt;parent = -1;
	now-&gt;data = 0;
	now-&gt;son = -1;
	now-&gt;putNode(0); //put in list

	if (!initialized)
	{
		for (int i=1; i&lt;MaxNodeCount; i++)
		{
			nodeList[i] = createSon();
		}
		initialized = true;
	}
	domino++;
}

bool DFS::hasBrother()
{
	if (hasParent())
	{
		if (getParent()-&gt;sonCount &gt; sonIndex+1)//has little brother
		{
			return true;
		}
	}
	return false;
}
</pre>
<pre><b><font color="#FF0000" size="3">//file StringSearch.cpp
</font></b>
#include &lt;iostream&gt;
#include &quot;DFS.h&quot;
#include &lt;fstream&gt;

using namespace std;

const int MaxRuleNum=10;

class StrSearching: public DFS
{
private:
	static int ruleNum;
	static char* ruleString[2][MaxRuleNum];
	static char* records[MaxLevel];
	char* createString(const char* input);
	char* curString;
	static int options[MaxRuleNum];
	char* replaceStr(char* source, char* target, int start, int size);
	void trackString();

protected:
	virtual bool validateOption(int sonData);
	virtual DFS* createSon();
	virtual void setStateCount();
	virtual bool evaluate();
	virtual void collectResult();
	virtual void onBeginSearch();
	virtual void onAfterAdded();
	virtual void onLeave();

public:
	void readFile(const char* fileName);
	virtual ~StrSearching();
};

char* StrSearching::records[MaxLevel];
int StrSearching::ruleNum = 0;
char* StrSearching::ruleString[2][MaxRuleNum];
int StrSearching::options[MaxRuleNum]={0};

int main()
{
	StrSearching S;
	S.readFile(&quot;c:\\strSearch.txt&quot;);
	S.beginCount(20, true);
	return 0;
}


void StrSearching::trackString()
{
	StrSearching* ptr = this;
	while(ptr!=NULL)
	{
		records[ptr-&gt;depth] = ptr-&gt;curString;
		if (ptr-&gt;hasParent())
		{
			ptr = (StrSearching*)ptr-&gt;getParent();
		}
		else
		{
			break;
		}
	}
}

StrSearching::~StrSearching()
{
//	delete []curString;
}


char* StrSearching::replaceStr(char* source, char* target, int start, int size)
{
	int targetSize = strlen(target);
	int newSize = strlen(source) + targetSize -size;
	char* result = new char[newSize+1];
	for (int i=0; i&lt;=newSize; i++)//copy null
	{
		if (i&lt;start)
		{
			result[i]= source[i];
		}
		else
		{
			if (i&lt;start+targetSize)
			{
				result[i] = target[i-start];
			}
			else
			{
				result[i] = source[i-targetSize+size];
			}
		}
	}
	return result;
}



void StrSearching::onLeave()
{
	StrSearching* ptr = (StrSearching*)getParent();
	StrSearching* sonPtr;
	if (ptr!=NULL)
	{
		for (int i=0; i&lt; ptr-&gt;sonCount; i++)
		{
			sonPtr = (StrSearching*)(getNode(ptr-&gt;son+i));
			delete []sonPtr-&gt;curString;
		}
	}
	DFS::onLeave();
}



bool StrSearching::validateOption(int sonData)
{
	char* pStr;
	StrSearching* ptr = this;
	if (strncmp(curString+state, ruleString[0][sonData], strlen(ruleString[0][sonData]))==0)
	{
		pStr = replaceStr(curString, ruleString[1][data], state, strlen(ruleString[0][data]));
		trackString();
		for (int i=0; i&lt;=depth; i++)
		{
			if (strcmp(records[i], pStr)==0)
			{
				delete []pStr;
				return false;
			}
		}
		delete []pStr;
		return true;
	}
	return false;
}

void StrSearching::onAfterAdded()
{
	curString = replaceStr(((StrSearching*)(getParent()))-&gt;curString, ruleString[1][data], 
		state, strlen(ruleString[0][data]));
}


void StrSearching::onBeginSearch()
{
	curString = createString(ruleString[0][ruleNum]);
}

bool StrSearching::evaluate()
{
	return strcmp(curString, ruleString[1][ruleNum])==0;
}

void StrSearching::collectResult()
{
	cout&lt;&lt;&quot;A solution\n&quot;;
	trackString();
	for (int i=0; i&lt;=depth; i++)
	{
		cout&lt;&lt;records[i]&lt;&lt;endl;
	}
}



void StrSearching::readFile(const char* fileName)
{
	ifstream in(fileName, ios::in);
	char buffer[2][20];
	in&gt;&gt;ruleNum;
	for (int i=0; i&lt; ruleNum+1; i++)
	{
		in&gt;&gt;buffer[0]&gt;&gt;buffer[1];
		ruleString[0][i] = createString(buffer[0]);
		ruleString[1][i] = createString(buffer[1]);
		options[i] = i;//0,1,2...
	}
	setOptions(options, ruleNum);
}

DFS* StrSearching::createSon()
{
	DFS* ptr = new StrSearching;
	return ptr;
}

char* StrSearching::createString(const char* input)
{
	char* result = new char[strlen(input)+1];
	if (result==NULL)
	{
		cout&lt;&lt;&quot;Unable allocate memory!\n&quot;;
	}
	else
	{
		strcpy(result, input);
	}
	return result;
}


void StrSearching::setStateCount()
{
	stateCount = strlen(curString);
}
	
</pre>
<pre>””</pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre><b><font color="#FF0000" size="3"><span lang="en-ca"><a name="result"></a>Running result of program:</span></font></b></pre>
<pre><span lang="en-ca"><font color="#FF0000"><b>You may notice in the solution of Code Competition 1, that &quot;big master&quot; suggest a breadth-first-search, cause it </b></font></span></pre>
<pre><span lang="en-ca"><font color="#FF0000"><b>will give you shortest answer for sure. Indeed, but a &quot;max level&quot; restricted &quot;depth-first-search&quot; will give you same</b></font></span></pre>
<pre><span lang="en-ca"><font color="#FF0000"><b>result as expected. And you can see there is one more solutions!</b></font></span></pre>
<pre></pre>
<pre>A solution
abab
baab
babcd
bbcdcd
bbad
bbabb
bbbab
bbbba
A solution
abab
baab
babcd
bbcdcd
bbcdcbb
bbabb
bbbab
bbbba
A solution
abab
baab
babcd
babcbb
bbcdcbb
bbabb
bbbab
bbbba
A solution
abab
abbcd
babcd
bbcdcd
bbad
bbabb
bbbab
bbbba
A solution
abab
abbcd
babcd
bbcdcd
bbcdcbb
bbabb
bbbab
bbbba
A solution
abab
abbcd
babcd
babcbb
bbcdcbb
bbabb
bbbab
bbbba
A solution
abab
abbcd
abbcbb
babcbb
bbcdcbb
bbabb
bbbab
bbbba
</pre>
<pre>	</pre>
<pre></pre>
<pre>			
</pre>

<pre></pre>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                                   
&nbsp;&nbsp;&nbsp; <a href="WhoAmI.htm">                  







                       <img src="picture/back.gif" style="border: medium none" alt="back.gif (341 bytes)" width="32" height="35"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<a href="index.htm"><img src="picture/up.gif" style="border: medium none" alt="up.gif (335 bytes)" width="35" height="32"></a>       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;                         
<img src="picture/next.gif" style="border: medium none" alt="next.gif (337 bytes)" width="32" height="35">          


</p>

</body>

</html>