<?xml version="1.0" encoding="utf-8"?><rss version="2.0">
<channel>
<title><![CDATA[业余空间]]></title>
<link>http://blog.pfan.cn/goal00001111</link>
<description>编程爱好者博客</description>
<language>zh-cn</language>
			<item>
		<title><![CDATA[我所理解的KMP算法（二）]]></title>
		<link>http://blog.pfan.cn/goal00001111/43214.html</link>
		<description><![CDATA[三．更好理解的失效函数

接下来我们看看另一些常见的失效函数表示方法。

在严蔚敏和吴伟民编著的《数据结构（C语言版）》（清华大学出版社）一书中，采用了一种比较简单的失效函数表示方法。它的定义与前面讲的失效函数差不多，只是把上述的四种情况简化为三种情况，将②和③合并为同一种类型，即若P[0…k-1] == P[j-k…j-1]，其中0 &lt; k &lt; j，则failure[j] = k，而不论P[k] 是否等于 P[j]。这样模式串P中就只有failure[0] = -1了，失效函数表示方法得到了简化——当然效率稍微有所降低。

采用这种失效函数表示方法，在求解失效函数时，可以利用简单的递推，根据failure[j]来得到failure[j+1]。

原理如下：

先给出两个概念：若存在0
&lt;= k &lt; j，且使得P[0…k] ==
P[j-k…j]的最大整数k，我们称P[0…k]为串P[0…j]的前缀子串，P[j-k…j]为串P[0…j]的后缀子串。

从failure[j]的定义出发，计算failure[j]就是要在串P[0…j]中找出最长的相等的前缀子串P[0…k]和后缀子串P[j-k…j]，这个查找的过程实际上仍是一个模式匹配的过程，只是目标和模式现在是同一个串P。

我们可以用递推的方法求failure[j]的值。

设已有failure[j] = k，则有0 &lt; k &lt; j，且P[0…k-1] == P[j-k…j-1]。接下来：

若P[k] == P[j]，则由failure[j]的定义可知failure[j+1] = k + 1 =
failure[j] + 1；

若P[k] != P[j]，则可以在前缀子串P[0…k]中寻找使得P[0…h-1] == P[k-h…k-1]的h，这时存在两种情况：

① 找到h，则由failure[j]的定义可知failure[k] = h，故P[0…h-1] == P[k-h…k-1] == P[j-h…j-1]，即在串P[0…j]中找到了长度为h的相等的前缀子串和后缀子串。

这时若P[h] == P[j]，则由failure[j]的定义可知failure[j+1] = h + 1 =
failure[k] + 1 = f]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2009-05-10 22:10:00</pubDate>
		</item>
				<item>
		<title><![CDATA[我所理解的KMP算法（一）]]></title>
		<link>http://blog.pfan.cn/goal00001111/43213.html</link>
		<description><![CDATA[我所理解的KMP算法

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作者：goal00001111（高粱）

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
始发于goal00001111的专栏；允许自由转载，但必须注明作者和出处

&nbsp;

一．简单字符串模式匹配算法的缺陷

设有目标串T(target)和模式串P(pattern)，模式匹配是指在目标串T中找到一个与模式串P相等的子串。模式匹配成功是指在目标串T中找到了一个模式串P。

简单字符串模式匹配算法（也就是BF算法）的基本思想是：从目标串T的起始比较位置pos开始（在后面的案例中，我们默认pos = 0），和模式串P的第一个字符比较之，若匹配，则继续逐个比较后继字符，否则从串T的下一个字符起再重新和串P的字符比较之。依此类推，直至串P中的每个字符依次和串T中的一个连续的字符序列（即匹配子串）相等，则称匹配成功，返回该匹配子串的首字符下标；否则成匹配不成功，返回-1。

BF算法的思想很直接，也很容易理解，其时间复杂度为O（lenT*lenP），其中lenT和lenP分别为串T和串P的长度。

我们先给出代码，再做简要分析：

/*

函数名称：BFIndex

函数功能：简单字符串模式匹配算法，若目标串T中从下标pos起存在和模式串P相同的子串，则称匹配成功，返回第一个匹配子串首字符的下标；否则返回-1。 

输入参数：const string &amp; T ：目标串T

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const string &amp; P
：模式串P

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int pos&nbsp;&nbsp;&nbsp;&nb]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2009-05-10 22:03:00</pubDate>
		</item>
				<item>
		<title><![CDATA[约瑟夫环问题算法集锦]]></title>
		<link>http://blog.pfan.cn/goal00001111/39774.html</link>
		<description><![CDATA[/*&nbsp; Name: 约瑟夫环问题算法集锦 &nbsp; Copyright: 始发于goal00001111的专栏；允许自由转载，但必须注明作者和出处&nbsp; Author: goal00001111搜集整理 &nbsp; Date: 03-12-08 18:14&nbsp; Description: 有编号从1到N的N个人坐成一圈报数，报到M的人出局，下一位再从1开始， 如此持续，直止剩下一位为止，报告此人的编号X。输入N,M，求出X。 共搜集整理了7类10种算法，对于初学者和算法爱好者来说——看了绝对值！ */#include&lt;iostream&gt;#include &lt;time.h&gt;using namespace std;int Fun_1(int n, int m);int Fun_2(int n, int m);int Fun_3(int n, int m);int Fun_4(int n, int m);int Fun_5(int n, int m);int Fun_6(int n, int m);int Fun_7(int n, int m);int Fun_8(int n, int m);int Fun_9(int n, int m);int Fun_10(int n, int m);int main(int argc, char* argv[]){&nbsp;&nbsp;&nbsp; int n, m;&nbsp;&nbsp;&nbsp; //cout &lt;&lt; "Input max, step: ";//&nbsp;&nbsp;&nbsp; cin &gt;&gt; n &gt;&gt; m;&nbsp;&nbsp;&nbsp; time_t startTime;&nbsp;&nbsp;&nbsp; time_t endTime;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; time(&amp;startTime);&nbsp;&nbsp;&nbsp; for (int i=10; i&lt;11; i++)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; Fun_1(i, 8);&nbsp;&nbsp;&nbsp; time]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-12-05 12:41:00</pubDate>
		</item>
				<item>
		<title><![CDATA[杨辉三角算法集锦]]></title>
		<link>http://blog.pfan.cn/goal00001111/39586.html</link>
		<description><![CDATA[/*&nbsp; Name: 杨辉三角算法集锦 &nbsp; Copyright: 始发于goal00001111的专栏；允许自由转载，但必须注明作者和出处&nbsp; Author: goal00001111&nbsp; Date: 27-11-08 19:04&nbsp; Description: &nbsp; 分别使用了二维数组，一维数组，队列，二项式公式，组合公式推论和递归方法等9种算法 &nbsp; 算法思路详见代码注释——注释很详细，呵呵 */#include&lt;iostream&gt;#include&lt;iomanip&gt;using namespace std;const int MAXROW = 40;void PrintBlank(int n);int Com(int n, int m);int Try(int row, int cel);void Fun_1(int row);void Fun_2(int row);void Fun_3(int row);void Fun_4(int row);void Fun_5(int row);void Fun_6(int row);void Fun_7(int row);void Fun_8(int row);void Fun_9(int row);int main(){&nbsp;&nbsp;&nbsp; int row;&nbsp;&nbsp;&nbsp; cin &gt;&gt; row;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Fun_1(row);&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;&nbsp;&nbsp;&nbsp; Fun_2(row);&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;&nbsp;&nbsp;&nbsp; Fun_3(row);&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;&nbsp;&nbsp;&nbsp; Fun_4(row);&nbsp;&nbsp;&nbsp; cout &lt;&lt; endl;&nbsp;&nbsp;&nbsp; Fun_5(row);&nbsp;&nbsp;&nbsp; cout &lt;&lt; en]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-11-27 19:18:00</pubDate>
		</item>
				<item>
		<title><![CDATA[有序全排列生成算法]]></title>
		<link>http://blog.pfan.cn/goal00001111/39515.html</link>
		<description><![CDATA[有序全排列生成算法
作者：goal00001111（高粱） 写本文的动力来自一个NOI题目：输出n个数的第m种全排列。
输入两个自然数m,n 1&lt;=n&lt;=20，1&lt;=m&lt;=n!
输出n个数的第m种全排列。
要解决这个问题，必须要生成有序的全排列。
生成n个
数字的全排列是算法学习中的一个经典案例，也是信息学奥赛中的一个常考内容，值得我们去深入研究。生成全排列的算法很多，大概分类有直接模拟法，设置中介
数法和数学分析法（这是我杜撰的一个名称），其中直接模拟法又可以分为递归和非递归模拟。设置中介数后，更是可以分为字典序全排列生成法，递增进位排列生
成算法，递减进位排列生成算法和循环左移排列生成算法等类别。此外还有邻位对换法和邻元素增值法等另类生成方法。利用这些算法生成的全排列，有些是有序全
排列，有些却是无序的，本文主要探讨有序全排列。
在上面列举的算法中，字典序全排列生成法和邻元素增值法，以及我杜撰的数学分析法可以生成有序全排列，即可以输出n个数的第m种全排列。其中字典序全排列
生成法根据是否设置中介数又可以分为两类，不用设置中介数的方法即直接模拟法。
我
们首先来看最简单的递归直接模拟法。这是普通递归方法的一个改进。普通的递归方法是利用将当前数组左界元素与其右侧的元素交换位置来实现排列，这样得到的
全排列是无序的。所以我们不能直接调换位置，而是将左界右侧的元素顺序右移，不破坏原排列的顺序，保证右侧元素的递增性。
为了回答本文开头提出的问题，我们统一设置一个接口void Permutation(long long n, long long
m);其中n表示共n个自然数，m表示第m种全排列。
在子程序中我们先创建一个数组a[n]来存储n个自然数，然后递归查找并输出n个数的第m种全排列。下面是主要的代码：（完整的代码附在文章后面，下同）
/*
函数名称：Permutation
函数功能：输出n个数的第m种全排列
输入变量：long long n：1，2，3，...，n共n个自然数（1&lt;=n&lt;=20） long long
m：第m种全排列（1&lt;=m&lt;=n!） 输出变量：无 */
void Permutation(long long n, long long m)// 递归直接模拟法]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-11-21 14:10:00</pubDate>
		</item>
				<item>
		<title><![CDATA[凯撒密码]]></title>
		<link>http://blog.pfan.cn/goal00001111/39101.html</link>
		<description><![CDATA[/*&nbsp; Name: &nbsp; Copyright: &nbsp; Author: &nbsp; Date: 25-10-08 20:34&nbsp; Description: &nbsp; 凯撒密码（caeser）是罗马扩张时期朱利斯o凯撒（Julius Caesar）创造的，用于加密通过信使传递的作战命令。它将字母表中的字母移动一定位置而实现加密。注意26个字母循环使用，z的后面可以堪称是a。 凯撒密码的加密算法极其简单。其加密过程如下：在这里，我们做此约定：明文记为m，密文记为c，加密变换记为E(key1,m)（其中key1为密钥），解密变换记为D(key2,m)（key2为解密密钥）（在这里key1=key2,不妨记为key）。凯撒密码的加密过程可记为如下一个变换：c≡m+key (mod n） （其中n为基本字符个数）同样，解密过程可表示为：m≡c+key (mod n） （其中n为基本字符个数）*/#include &lt;iostream&gt;#include &lt;fstream&gt;#include &lt;vector&gt;#include &lt;string&gt;using namespace std;bool ReadFile(vector&lt;string&gt; &amp; article, char * fileName);bool WriteFile(const vector&lt;string&gt; &amp; article, char * fileName);void Encrypt(const vector&lt;string&gt; &amp; proclaimedInWriting, vector&lt;string&gt; &amp; cryptograph, int key);void Decode(const vector&lt;string&gt; &amp; cryptograph, vector&lt;string&gt; &amp; proclaimedInWriting, int key);int main(void){&nbsp;&nbsp;&nbsp; &nbsp;vector&lt;string&gt; article, proclaimedInWriting, crypt]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-10-25 20:37:00</pubDate>
		</item>
				<item>
		<title><![CDATA[模运算及其应用]]></title>
		<link>http://blog.pfan.cn/goal00001111/39093.html</link>
		<description><![CDATA[模运算及其应用

goal00001111搜集整理

&nbsp;

摘要：模运算在数论和程序设计中应用很广泛，从奇偶数的判别到素数的判别，从模幂运算到最大公约数的求法，从孙子问题到凯撒密码问题，无不充斥着模运算的身影。本文从模运算的概念，性质，到模运算的基本应用，较为全面的介绍了模运算及其编程方法。

关键词：模运算 程序设计
应用

&nbsp;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 模运算在数论和程序设计中都有着广泛的应用，从奇偶数的判别到素数的判别，从模幂运算到最大公约数的求法，从孙子问题到凯撒密码问题，无不充斥着模运算的身影。虽然很多数论教材上对模运算都有一定的介绍，但多数都是以纯理论为主，对于模运算在程序设计中的应用涉及不多。本文以c++语言为载体，对基本的模运算应用进行了分析和程序设计，以理论和实际相结合的方法向大家介绍模运算的基本应用。。

&nbsp;

一 基本理论：

基本概念：

给定一个正整数p，任意一个整数n，一定存在等式 &nbsp;n&nbsp;=&nbsp;kp&nbsp;+&nbsp;r
；
其中k、r是整数，且&nbsp;0&nbsp;≤&nbsp;r&nbsp;&lt;&nbsp;p，称呼k为n除以p的商，r为n除以p的余数。

对于正整数p和整数a,b，定义如下运算：&nbsp; 
取模运算：a % p（或a mod p），表示a除以p的余数。&nbsp; 

模p加法：(a + b) % p ，其结果是a+b算术和除以p的余数，也就是说，(a+b) = kp +r，则(a + b) % p = r。&nbsp; 

模p减法：(a-b) % p ，其结果是a-b算术差除以p的余数。&nbsp; 

模p乘法：(a * b) % p，其结果是 a * b算术乘法除以p的余数。&nbsp; 
说明：

1. 同余式：正整数a，b对p取模，它们的余数相同，记做 a ≡ b % p或者a ≡ b (mod p)。

2. n %&nbsp;p得到结果的正负由被除数n决定,与p无关。例如：7%4 = 3， -7%4 = -3， 7%-4 = 3， -7%-4 = -3。



基本性质：

（1）若p|]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-10-25 11:59:00</pubDate>
		</item>
				<item>
		<title><![CDATA[二进制在数学中的妙用]]></title>
		<link>http://blog.pfan.cn/goal00001111/36142.html</link>
		<description><![CDATA[二进制在数学中的妙用

goal00001111搜集整理

&nbsp;

十八世纪初，莱布尼茨发明了二进制数，当时的他肯定没有预料到二进制在信息时代会有着如此广泛的应用。二进制数以其工作可靠，运算简单，逻辑严密，容易实现等特点，成为了计算机的专用语言。在计算机科学和大量应用数学领域中，二进制记数法是必不可少的。在趣味数学方面，同样也有广泛的应用。

让我们先来看一个经典的数学趣题：

一工人工作7天，老板有一段黄金，每天要给工人1/7的黄金作为工资，老板只能切这段黄金2刀，请问怎样切才能每天都给工人1/7的黄金？

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这题不简单吧？小心别把脑子都想破了。

在给出答案之前，先让我们看另一个简单的例子：

用天平称1~63克整数克重的物品，至少要配备几只多重的砝码（砝码只能放在天平的一端）？

没有学过二进制的人是很难想到答案的，可是如果你知道二进制数，那就不难了。我们知道二进制中只有0和1两个数字，它的各位数字的权值从小到大依次为2^0，2^1，2^2，2^3，。。。。我们用一个数的每位数字乘以其权值所得到的乘积之和来表示这个数。对于一个具有8位的二进制数来说，它可以表示的数据范围是0~2^8。

63 = 2^6 – 1 =
2^0 + 2^1 + 2^2 + 2^3 + 2^4 + 2^5

所以，我们只需配备2^0 =1，2^1 = 2，2^2 = 4，2^3 = 8，2^4 = 16，2^5 = 32五种不同克数的砝码各一个。

类似的题目还有如何装苹果：

现有一笔出售苹果的生意，已知客人可能需要的苹果数量肯定是1个到1000个之间，但不知道具体数字。客人要求必须全部用他提供的箱子装整箱（每个箱子都最多可以装1000个苹果），箱子一旦装成就无法再拆开重装。

你手中有1000个苹果，10个箱子，客人需要的苹果数量未知，问怎么装才能满足客人的需要？

解题的原理和上题是一样的，都是利用二进制数的记数原理。因为1000 &lt; 2^10 = 1024，所以只要使用2^0，2^1，2^2，2^3，2^4，2^5，2^6，2^7，2^8，2^9十个数，就可以表示1到1023之间的所有数。

例如：30 = 2^1 +]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-06-15 16:39:00</pubDate>
		</item>
				<item>
		<title><![CDATA[我学c++Builder系列(7)]]></title>
		<link>http://blog.pfan.cn/goal00001111/35439.html</link>
		<description><![CDATA[10，由系统给出正确答案

算法思路：当你希望获取更多的解或者更快的得到答案的话，就可以使用这个功能。我采用穷举的方法，让计算机列出参与运算的数字和符号的各种排列方式，并按照基本运算原则进行计算，最后详细分析了出现括号的各种情况，并以规定的格式进行输出。

新建一个Unit文件“UnitAnswer”，打开UnitAnswer.h，加入如下代码：

//---------------------------------------------------------------------------

#ifndef UnitAnswerH

#define UnitAnswerH

&nbsp;

#include &lt;vcl.h&gt;

&nbsp;

//穷举法列出参与运算的数字的各种排列方式

void CunShuZi(int num[]);

&nbsp;

//回溯法输出各个可能的正确答案

void CunFuHao(int xuhao);

&nbsp;

//根据序号返回对应的运算符

char FuHao(int i);

&nbsp;

//计算当前四则运算表达式，并返回计算结果

int JiSuan(void);

&nbsp;

//记录正确答案到文本文件中

void Print(int n);

//---------------------------------------------------------------------------

#endif

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后切换到UnitAnswer.cpp，实现上述自定义函数。

//---------------------------------------------------------------------------

#pragma hdrstop

&nbsp;

#include "UnitAnswer.h"

//-----------------------------------------------------------------------]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-05-25 15:14:00</pubDate>
		</item>
				<item>
		<title><![CDATA[我学c++Builder系列(6)]]></title>
		<link>http://blog.pfan.cn/goal00001111/35438.html</link>
		<description><![CDATA[8，计算表达式结果算法思路：此游戏的难点是如何将一个字符串形式的表达式解析成计算机能计算的算术表达式。我们的想法是按照数学四则运算法则，先去掉括号，然后按照先乘除后加减的顺序计算。按照这种思路，我们必须解决如何寻找匹配的符号，如何寻找算术符号两边的数字，如何定位第一个算术符号的位置等问题。&nbsp;&nbsp;&nbsp;&nbsp;新建一个Unit文件“UnitComputer”，打开UnitComputer.h，加入如下代码：//---------------------------------------------------------------------------#ifndef&nbsp;UnitComputerH#define&nbsp;UnitComputerH#include&nbsp;&lt;vcl.h&gt;//定位第一个算术符号的位置，如果没有算术符号，则返回0int&nbsp;AnyFirstPos(String&nbsp;str);//定位最后一个算术符号的位置，如果没有算术符号，则返回0int&nbsp;AnyLastPos(String&nbsp;str);//返回最先出现的算术符号char&nbsp;AnyFirstF(String&nbsp;str);//计算不带()号的四则运算,先乘除，后加减int&nbsp;SubCompute(String&nbsp;str);//计算带()号的四则运算表达式int&nbsp;TotalCompute(String&nbsp;str);//---------------------------------------------------------------------------#endif&nbsp;&nbsp;&nbsp;&nbsp;然后切换到UnitComputer.cpp，实现上述自定义函数。//---------------------------------------------------------------------------#pragma&nbsp;hdrstop#include&nbsp;"UnitComputer.h"//--------------------------------------------------------------]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-05-25 15:13:00</pubDate>
		</item>
				<item>
		<title><![CDATA[我学c++Builder系列(5)]]></title>
		<link>http://blog.pfan.cn/goal00001111/35437.html</link>
		<description><![CDATA[三，添加事件处理：1，&nbsp;&nbsp;&nbsp;&nbsp;窗体的构造函数：先在UnitMain.h中增加两个私有属性int&nbsp;ColorData[4];和int&nbsp;SpendTime;分别用来存储扑克牌图片信息和用户花费的时间。然后切换到UnitMain.cpp中，在窗体Form1的构造函数中，加入下列代码，用于初始化变量和组件：__fastcall&nbsp;TForm1::TForm1(TComponent*&nbsp;Owner)&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;TForm(Owner){&nbsp;&nbsp;&nbsp;&nbsp;ZeroMemory(ColorData,&nbsp;0);&nbsp;&nbsp;&nbsp;&nbsp;SpendTime&nbsp;=&nbsp;0;}2，“开始”按钮的OnClick事件处理功能：点击“开始”按钮时，系统随机地发出四张纸牌，显示在四个Image组件中。并将“开始”按钮文字改变为“重新开始”。代码：void&nbsp;__fastcall&nbsp;TForm1::Button1Click(TObject&nbsp;*Sender){&nbsp;&nbsp;&nbsp;&nbsp;randomize();&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i=0;&nbsp;i&lt;4;&nbsp;i++)&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ColorData[i]&nbsp;=&nbsp;random(10)&nbsp;+&nbsp;1;&nbsp;&nbsp;//随机给出扑克牌的点数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;FileName&nbsp;=&nbsp;"扑克牌图片\\dw_";&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;num&nbsp;=&nbsp;random(4);&nbsp;&nbsp;&nbsp;//随机给出扑克牌的花色&nbsp;&n]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-05-25 15:12:00</pubDate>
		</item>
				<item>
		<title><![CDATA[我学c++Builder系列(4)]]></title>
		<link>http://blog.pfan.cn/goal00001111/35436.html</link>
		<description><![CDATA[速算24游戏

&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作者：goal00001111

&nbsp;

一，程序效果说明：

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 速算24游戏的规则是由系统发出4张扑克牌，要求用户利用扑克牌显示的数字，通过加减乘除运算得出24（可使用括号），为了计算方便，不会出现J,Q,K和王牌。

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当启动应用程序后，程序界面如图1所示。



&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 点击“开始”按钮，游戏开始，系统将发出4张扑克牌。这时游戏的界面如图2所示。



&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这时用户利用扑克牌显示的数字，通过加减乘除运算，以最快的速度得出24（可使用括号）。然后在文本框中写好表达式，接着点击“计算”按钮。这时系统会计算输入表达式的结果，并告诉用户答案是否正确。

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如下图所示分别是计算正确和错误的界面。

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果错了可以再次输入新的表达式，重复上一步。直到您的表达式正确，这时系统会恭喜你算对了。

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 游戏还可以计算用户花费的时间，并且能够判断用户的输入是否出现了错误和屏蔽一些不正确的输入，如字母和其他非法字符等等。

&nbsp;&nbsp;]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-05-25 15:02:00</pubDate>
		</item>
				<item>
		<title><![CDATA[浅析OnKeyPress事件和OnKeyDown/OnKeyUp事件]]></title>
		<link>http://blog.pfan.cn/goal00001111/35244.html</link>
		<description><![CDATA[浅析OnKeyPress事件和OnKeyDown/OnKeyUp事件



&nbsp;OnKeyPress事件

&nbsp;&nbsp;&nbsp; OnKeyPress事件是在用户按下键盘上任何一个可打印的字符时发生，只有能接收键盘输入的组件才有OnKeyPress事件。我们常常利用OnKeyPress事件截取在编辑框和组合框组件中所输入的击键，还可以立即测试击键的有效性或在字符输入时对其进行一定的格式处理。

&nbsp;&nbsp;&nbsp; 例如，在TEdit组件上捕获OnKeyPress事件，判断输入的是否是小写字母，如果是，将其转换为大写字母，代码如下：

&nbsp;&nbsp;&nbsp; void
__fastcall TForm1::Edit1KeyPress(TObject *Sender, char &amp;Key)

{

&nbsp;&nbsp;&nbsp; if (Key &gt;= 'a' &amp;&amp; Key
&lt;= 'z')

&nbsp;&nbsp;&nbsp; {

&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Key
+= 'A' - 'a';

&nbsp;&nbsp;&nbsp; }

}

将Key的值改变为0时可取消击键，这样一来对象便接收不到字符，我们可以利用这个特点来屏蔽某些字符。例如，有时候我们只允许用户输入数字，则加入如下代码：

void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &amp;Key)

{

 &nbsp;&nbsp;&nbsp; if
(Key &lt; '0' || Key &gt; '9')

&nbsp;&nbsp;&nbsp; {

&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Key
= 0;//取消刚才输入的字符

&nbsp;&nbsp;&nbsp; }

}

注意：OnKeyPress事件可以引用任何可打印的键盘字符，一个来自标准字母表的字符或少数几个特殊字符之一的字符与 CTRL 键的组合，以及 ENTER 或 BACKSPACE 键，但它]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2008-05-20 15:22:00</pubDate>
		</item>
				<item>
		<title><![CDATA[C++builder组件属性详解（1）]]></title>
		<link>http://blog.pfan.cn/goal00001111/31202.html</link>
		<description><![CDATA[C++builder组件属性详解

尽管C++Builder的组件种类繁多，每种组件又都有许多不同的属性，但是在这些众多的属性中有相当一部分是大多数组件所共有的。因此我们应当主要掌握这些共有组件。
	在设计时设置属性一般是通过属性窗口来进行的。在属性窗口设置组件属性的操作步骤如下：
1）	打开相应对象的属性窗口。
2）	从属性列表中选定属性名称。
3）	在属性窗口的右列输入或选择新的属性值。
注意：有些属性在设置值右侧有…按钮，单击该按钮会出现相应的设置对话框，设置值需要在对话框中选定。
在代码中设置组件属性的方法是：
对象名称->属性名称 ＝ 设置值；
下面我们来介绍一些主要组件的主要属性。

窗体form的属性：
1．Caption：标题。是窗体和各种可视化控件的共有属性，用来指定窗体标题栏中的说明文字，默认与控件名相同，但程序员可以在对象监视器和代码中修改。
在代码中修改的格式为：Form->Caption = "da";// da表示程序员输入的标题。
通常，对于Windows系统中的多文档界面( MDI )应用程序，当主框架窗口中的子窗口以最大化显示的时候，应用程序的标题栏中显示的内容为“  - ”；当子窗口以非最大化窗口显示的时候，主框架窗口中只显示应用程序的名称，子窗口有自己的标题栏，其中显示该窗口打开的文件名。所以，当窗体的显示方式发生了改变后，应该立即改变标题栏中的内容。

2．Name：变量名。是窗体和所有控件的共有属性，系统给予其默认名字，但程序员可以在对象监视器修改，不要在代码中修改。
	通常，应该在系统开发的设计阶段就将整个工程中所有窗体的名称确定，然后在编程阶段，根据设计文档修改窗体的Name属性。一般情况下，不要在程序运行期间通过代码修改Name属性。

3．Enabled：可操作性。决定了对象在运行时是否允许用户进行操作。
它是逻辑型：true表示允许用户操作并可对其操作作出响应；false表示禁止用户操作，此时对象呈灰色。
程序员可以在对象监视器和代码中修改属性Enabled。
在代码中修改的格式为：Form-> Enabled = da;// da可以是true或false。

4．Visible：可见性。决定了对象在运行时是否可见。
	它也是逻辑型：true表示可见；false]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-11-30 18:30:00</pubDate>
		</item>
				<item>
		<title><![CDATA[代理服务器(Proxy)完全解析(转帖)]]></title>
		<link>http://blog.pfan.cn/goal00001111/30050.html</link>
		<description><![CDATA[代理服务器(Proxy)完全解析2002-01-04 10:07:00· 约翰牛· linkwanhttp://www.yesky.com/20011130/207727.shtml
相信，提起代理服务器(Proxy)还是有非常多的人关注的，因为无论是在线论坛(bbs)或者是新闻组里面，作为一个撰稿人，我的信箱里也经常收到询问代理服务器为何物，或者如何设置代理服务器这类的问题，所以，我觉得有必要总结一下，把我对代理服务器的认识和在实际应用中各种相关网络应用软件的代理服务器设置告诉大家，这就是本文写就的来由了。&nbsp; 
　　什么是代理服务器(Proxy)？ 
　　什么是代理服务器呢？ 
　　如果我告诉你，用代理服务器可以免费访问Internet，可以加速访问速度，可以访问无法直接访问的站点，可以部分解决网络IP地址紧缺的问题……，您一定认为，天下哪有这等美事？如果您能耐心看完冗长的本文，您就会确信我说的话毫不夸张，如果应用得当，可以每月为您节省一笔可观的上网费用，就用不着每个月战战兢兢的跑到电信局一五一十的把"血汗钱""捐献"给ISP了。 
　　代理服务器的工作机制 
　　代理服务器的工作机制很象我们生活中常常提及的代理商，假设你自己的机器为A机，你想获得的数据由服务器B提供，代理服务器为C，那么具体的连接过程是这样的。 
　　首先，A机需要B机的数据，A直接与C机建立连接，C机接收到A机的数据请求后，与B机建立连接，下载A机所请求的B机上的数据到本地，再将此数据发送至A机，完成代理任务。 
　　代理服务器存在的理由 
　　或许你要问了，何必这么麻烦呢？A机与B机直接建立不是很好么？请耐心听我讲完，使用代理服务器当然有其存在的合理理由： 
　　1、局域局内没有与外网相连的机器通过内网的代理服务器连接到外网。这个例子，最有说服力的就是小办公室的上网解决方案了，利用办公室原有的局域网，只要简单的利用一根电话线、一个合法帐号(在ISP初申请得到拨号号码和用户名和密码)，加上一个简单的代理软件(如Sygate，WinGate,Winrouter)就可以方便的以最小的花费将整个办公室的电脑与互联网络相连接。 
　　2、为了获得更大的速度，通过频宽较大的proxy与目标主机连接。访问台湾部分站点的速度大家相必已经领教过了，如果我们使用一个位于美国的代理]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-12 21:45:00</pubDate>
		</item>
				<item>
		<title><![CDATA[什么是端口？(转帖)]]></title>
		<link>http://blog.pfan.cn/goal00001111/30047.html</link>
		<description><![CDATA[什么是端口？
&nbsp;&nbsp;&nbsp; 可以这样说：端口便是计算机与外部通信的途径，没有它，计算机便又聋又哑。
&nbsp;&nbsp;&nbsp; 在网络技术中，端口（Port）有好几种意思。集线器、交换机、路由 器的端口指的是连接其他网络设备的接口，如RJ-45端口、Serial端口等。我们 这里所指的端口不是指物理意义上的端口，而是特指TCP/IP协议中的端口，是逻辑意义上的端口。 
&nbsp;&nbsp;&nbsp; 那么TCP/IP协议中的端口指的是什么呢？如果把IP地址比作一间房子 ，端口就是出入这间房子的门。真正的房子只有几个门，但是一个IP地址的端口 可以有65536个之多！端口是通过端口号来标记的，端口号只有整数，范围是从0 到65535。 
&nbsp;&nbsp;&nbsp; 端口有什么用呢？我们知道，一台拥有IP地址的主机可以提供许多服务，比如Web服务、ftp服务、SMTP服务等，这些服务完全可以通过1个IP地址来实现。那么，主机是怎样区分不同的网络服务呢？显然不能只靠IP地址，因为IP地址与网络服务的关系是一对多的关系。实际上是通过“IP地址+端口号”来区分不同的服务的。
&nbsp;&nbsp;&nbsp; 需要注意的是，端口并不是一一对应的。比如你的电脑作为客户机访 问一台WWW服务器时，WWW服务器使用“80”端口与你的电脑通信，但你的电脑则 可能使用“3457”这样的端口，如图1所示。 
　　图1
&nbsp;&nbsp;&nbsp; 按对应的协议类型，端口有两种：TCP端口和UDP端口。由于TCP和UDP 两个协议是独立的，因此各自的端口号也相互独立，比如TCP有235端口，UDP也 可以有235端口，两者并不冲突。 
&nbsp;&nbsp;&nbsp; 现在讲一下什么是端口号，一个端口就是一个潜在的通讯通道，也是一个入侵通道，开放一个端口就是一台计算机在网络上打开了一扇窗户，黑客入侵的方法就是用手工扫描或利用扫描软件找到服务器所开放的端口，去根据其相应的漏洞对服务器进行入侵或攻击，因此对端口的了解是非常重要的。 
　　 端口大概分为三类： 
　　1：公认端口（well known ports）:范围从0到1023，他们是绑定于一些服务。通常这些端口的通信明确表明了某种服务的协议。其中80端口]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-12 21:04:00</pubDate>
		</item>
				<item>
		<title><![CDATA[如何隐藏自己的IP地址?(转帖)]]></title>
		<link>http://blog.pfan.cn/goal00001111/30046.html</link>
		<description><![CDATA[首先说说隐藏真实IP的方法，最简单的方法就是使用代理服务器。与直接连接到Internet相比，使用代理服务器能保护上网用户的IP地址，从而保障上网安全。代理服务器的原理是在客户机和远程服务器之间架设一个“中转站”，当客户机向远程服务器提出服务要求后，代理服务器首先截取用户的请求，然后代理服务器将服务请求转交远程服务器，从而实现客户机和远程服务器之间的联系。很显然，使用代理服务器后远端服务器包括其它用户只能探测到代理服务器的IP地址而不是用户的IP地址，这就实现了隐藏用户IP地址的目的，保障了用户上网安全。而且，这样还有一个好处，那就是如果有许多用户共用一个代理器时，当有人访问过某一站点后，所访问的内容便会保存在代理服务器的硬盘上，如果再有人访问该站点，这些内容便会直接从代理服务器中获取，而不必再次连接远端服务器，因此可以节约带宽，提高访问速度。 &nbsp; &nbsp;&nbsp;建议您最好用免费代理服务器，寻找免费代理服务器的方法有很多，你可以试试用ProxyHunter（代理猎手），它能自动为您搜索出多个免费代理服务器，并验证各个服务器的连接速度，从而让你选择最佳途径。更重要的是，代理服务器不仅支持浏览软件，而且支持电子邮件、FTP、下载、离线浏览等功能软件，可谓无所不在。【点击下载代理猎手 3.1】。不过这种方法比较费时、费事，建议不到万不得以时还是不用为好。最好的方法是使用现成的免费代理服务器，现在网上有不少网站定期提供最新的免费代理服务器，如这里提供的代理服务器的更新速度就非常快，而且各种类型的代理都有：http://www.emaga.net/8341/myann/index.asp 。建议大家把这个网页放入你的收藏夹，这样你就再也不用为找不到好的免费代理服务器而发愁了。 &nbsp;&nbsp; &nbsp;找到免费代理服务器后，就可以使用它了。以IE浏览器为例，运行IE，点击“工具”→“Interner选项”，在弹出的“Interner选项”对话框中选择“连接”标签，再点击“设置”按钮，在弹出的对话框中把“对此连接使用代理服务器”前面的框勾选上，然后在“地址”和“端口”栏中填入你找到的代理服务器IP和所用端口即可。 &nbsp;&nbsp;&nbsp; 同时在“高级”设置中你还可以对不同的服务器，例如HTTP、FTP设定不同的代理服务器地址和端口。]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-12 20:37:00</pubDate>
		</item>
				<item>
		<title><![CDATA[特殊用途的IP地址介绍(转帖)]]></title>
		<link>http://blog.pfan.cn/goal00001111/30045.html</link>
		<description><![CDATA[特殊用途的IP地址介绍
一、0.0.0.0 
&nbsp;&nbsp;&nbsp; 严格说来，0.0.0.0已经不是一个真正意义上的IP地址了。它表示的是这样一个集合：所有不清楚的主机和目的网络。这里的“不清楚”是指在本机的路由表里没有特定条目指明如何到达。对本机来说，它就是一个“收容所”，所有不认识的“三无”人员，一律送进去。如果你在网络设置中设置了缺省网关，那么Windows系统会自动产生一个目的地址为0.0.0.0的缺省路由。 
&nbsp;
&nbsp;&nbsp;&nbsp; 二、255.255.255.255 
&nbsp;&nbsp;&nbsp; 限制广播地址。对本机来说，这个地址指本网段内(同一广播域)的所有主机。如果翻译成人类的语言，应该是这样：“这个房间里的所有人都注意了！”这个地址不能被路由器转发。 
&nbsp;
&nbsp;&nbsp;&nbsp; 三、127.0.0.1 
&nbsp;&nbsp;&nbsp; 本机地址，主要用于测试。用汉语表示，就是“我自己”。在Windows系统中，这个地址有一个别名“Localhost”。寻址这样一个地址，是不能把它发到网络接口的。除非出错，否则在传输介质上永远不应该出现目的地址为“127.0.0.1”的数据包。 
&nbsp;
&nbsp;&nbsp;&nbsp; 四、224.0.0.1 
&nbsp;&nbsp;&nbsp; 组播地址，注意它和广播的区别。从224.0.0.0到239.255.255.255都是这样的地址。224.0.0.1特指所有主机，224.0.0.2特指所有路由器。这样的地址多用于一些特定的程序以及多媒体程序。如果你的主机开启了IRDP(Internet路由发现协议，使用组播功能)功能，那么你的主机路由表中应该有这样一条路由。 
&nbsp;
&nbsp;&nbsp;&nbsp; 五、169.254.x.x 
&nbsp;&nbsp;&nbsp; 如果你的主机使用了DHCP功能自动获得一个IP地址，那么当你的DHCP服务器发生故障，或响应时间太长而超出了一个系统规定的时间，Wingdows系统会为你分配这样一个地址。如果你发现你的主机IP地址是一个诸如此类的地址，很不幸，十有八九是你的网络不能正常运行了。 
&nbsp;
&nbsp;&nbsp]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-12 20:26:00</pubDate>
		</item>
				<item>
		<title><![CDATA[什么是IP地址？(转帖)]]></title>
		<link>http://blog.pfan.cn/goal00001111/30044.html</link>
		<description><![CDATA[随着电脑技术的逐步普及和因特网技术的迅猛发展，学习因特网、利用因特网已不再是那些腰缠万贯的大款和戴者深度眼睛的专业技术人员的专利，它已作为二十一世纪人类的一种新的生活方式而逐步深入到寻常百姓家。谈到因特网，IP地址就不能不提，因为无论是从学习还是使用因特网的角度来看，IP地址都是一个十分重要的概念，INTERNET的许多服务和特点都是通过IP地址体现出来的。 
&nbsp;
一、IP地址的概念　　 
　　我们知道因特网是全世界范围内的计算机联为一体而构成的通信网络的总称。联在某个网络上的两台计算机之间在相互通信时，在它们所传送的数据包里都会含有某些附加信息，这些附加信息就是发送数据的计算机的地址和接受数据的计算机的地址。象这样，人们为了通信的方便给每一台计算机都事先分配一个类似我们日常生活中的电话号码一样的标识地址，该标识地址就是我们今天所要介绍的IP地址。根据TCP/IP协议规定，IP地址是由32位二进制数组成，而且在INTERNET范围内是唯一的。例如，某台联在因特网上的计算机的IP地址为： 
11010010 01001001 10001100 00000010 
&nbsp;&nbsp; 很明显，这些数字对于人来说不太好记忆。人们为了方便记忆，就将组成计算机的IP地址的32位二进制分成四段，每段8位，中间用小数点隔开，然后将每八位二进制转换成十进制数，这样上述计算机的IP地址就变成了：210.73.140.2。 
&nbsp;
二、IP地址的分类　　 
　　我们说过因特网是把全世界的无数个网络连接起来的一个庞大的网间网，每个网络中的计算机通过其自身的IP地址而被唯一标识的，据此我们也可以设想，在INTERNET上这个庞大的网间网中，每个网络也有自己的标识符。这与我们日常生活中的电话号码很相像，例如有一个电话号码为0515163，这个号码中的前四位表示该电话是属于哪个地区的，后面的数字表示该地区的某个电话号码。与上面的例子类似，我们把计算机的IP地址也分成两部分，分别为网络标识和主机标识。同一个物理网络上的所有主机都用同一个网络标识，网络上的一个主机（包括网络上工作站、服务器和路由器等）都有一个主机标识与其对应。IP地址的4个字节划分为2个部分，一部分用以标明具体的网络段，即网络标识；另一部分用以标明具体的节点，即主机标识，也就是说某个网络中的]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-12 20:25:00</pubDate>
		</item>
				<item>
		<title><![CDATA[算法设计之分治法(4)]]></title>
		<link>http://blog.pfan.cn/goal00001111/29990.html</link>
		<description><![CDATA[参考程序
1．常规算法，复杂度为O(N):
double Power(double x, unsigned int N)
{
&nbsp;&nbsp;&nbsp; double result = 1.0;
&nbsp;&nbsp;&nbsp; for (unsigned int i=0; i&lt;N; i++)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; result *= x;
&nbsp;&nbsp;&nbsp; return result;
}
折半算法（二分法），复杂度为O(logN):
double Power(double x, unsigned int N)
{
&nbsp;&nbsp;&nbsp; if (N == 0)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return 1.0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp; double t = Power(x, N/2);
&nbsp;&nbsp;&nbsp; if (N % 2 == 0)
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return t * t;
&nbsp;&nbsp;&nbsp; else
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return t * t * x;
}
2．算法分析：在讲解枚举法时，我们讨论了如何用枚举法求解此题，但如果求解的精度进一步提高，使用枚举法就无能为力了，在此我们再一次讨论如何用二分法求解此题。
由题意知（i,i+1）中若有根，则只有一个根，我们枚举根的值域中的每一个整数x(-100≤x≤100),设定搜索区间[x1，x2]，其中x1=x，x2=x+1。若：
⑴f(x1)=0，则确定x1为f(x)的根；
⑵f(x1)*f(x2)&lt;0，则确定根x在区间[x1，x2]内。
⑶f(x1)*f(x2)&gt;0，则确定根x不在区间[x1，x2]内，设定[x2，x2+1]为下一个搜索区间；
若确定根x在区间[x1，x2]内，采用二分法，将区间[x1，x2]分成左右两个子区间：
左子区间]]></description>
		<author><![CDATA[goal00001111]]></author>
		<pubDate>2007-10-09 10:52:00</pubDate>
		</item>
		</channel>
</rss>