代码风暴

#include "sort.h"
#include <iostream>
#include <vector>
using namespace std;
//指针检查为空!!
//指针检查为空!!
//指针检查为空!!
void Josephus(int n,int m)//约瑟夫环 n个人环状每次数到m就出列,少于20人
{						  // 如果第一次删除第m个,那么直接把 t 的初值改为m
	//int p[20]={0};
	int *p = new int[n];
	int i,j,t=0;
	for (i=0;i<n;i++)
	{
		p[i]=i+1;		//给每个人的编号
	}
	for (j=n;j>=1;j--)	//精彩的地方是这里,安排的巧妙,从n开始,这是人的总数
	{
		t=(t+m-1)%j;		// 输出来的编号 下标,与数组本身的值无关!!
		cout<<"输出的编号是:"<<p[t]<<endl;   // t 编号 牛逼
		for (int k=t;k<n;k++)
		{
			p[k]=p[k+1];//填补出列的;   从出列的位置开始
		}
	}
	delete[] p;//这里不能忘记!!!!!!!!!!
}

void quick_sort(int *arr,int start,int last)//arr待排序的数组,对区间[l len]之间的数组进行排序
{
	int i=start,j=last,temp;//注意数组越界的问题 
	int tem=arr[start];
	if (start<last)
	{
		//tem=arr[start];
		while(i!=j)
		{
			while(j>i&&arr[j]>tem)//数组越界隐患
				j--;
			//arr[i]=arr[j];
			while(i<j&&arr[i]<tem)
				i++;
			//arr[j]=arr[i];  
			if (i<=j)
			{
				temp=arr[i];
				arr[i]=arr[j];
				arr[j]=temp;
			}
		}
		//arr[i]=tem;
		quick_sort(arr,start,i-1);
		quick_sort(arr,i+1,last);
	}
}
void select_sort(int arr[],int len)
{
	int max=0,temp;
	for (int i=0;i<len;i++)
	{
		max=i;//这里很关键,标识符
		for (int j=i+1;j<len;j++)
		{
			if(arr[j]<arr[max]) //注意这里 i,希望赋给最小值序号
				max=j;
		}
		if (max!=i)//如果max没有变化就说明a[i]是最小值,不用交换
		{
			temp=arr[i];
			arr[i]=arr[max];
			arr[max]=temp;
		} 
	}
}
//template<typename Comparable>
void insert_sort(int a[],int len) 
{
	int j,i,tmp;
	int cur=0;
	bool state=false;
	for (int p=0;p<len-1;p++)
	{
		//Comparable tem=a[p];
		//for (j=p+1;j<a.size();j++)
		//{
		//	if (a[j]>a[p])
		//	{
		//		a[p]=a[j]; 
		//		cur=j;
		//	}   
		//}   
		//if (tem!=a[p])  //如果执行了if(a[j]>a[p])语句,说明a[p] 发生了变化,说明最大值不是自身
		//						//,以此为条件判断
		//{
		//	a[cur]=tem;
		//}


		for (i=1;i<len;i++)
		{
			tmp=a[i];
			j=i-1;
			while(j>=0&&tmp<a[j]) //核心代码,移位
			{
				a[j+1]=a[j];
				j--;
			}
			a[j+1]=tmp; 
		}
	}

}
void shell_sort(int arr[],int len) //也是插入排序的一种,插入排序是一个无序的第一个数											
{														//的插入到一个有序的
	int temp=0,j;
	int gap=len/2;
	while(gap>0)
	{
		for (int i=gap;i<len;i++)
		{
			temp=arr[i];
			j=i-gap;
			while(j>=0&&arr[j]>temp)
			{
				arr[j+gap]=arr[j];
				j=j-gap;
			}
			arr[j+gap]=temp;
		}
		gap/=2;
	}
}
void sift(int arr[],int low,int high)//区间[low,high],不断的构造二叉堆,
{														//大的到根部去,小的到叶子去
	int i=low;
	int j=2*i;
	int temp=arr[i];
	while(j<=high)
	{
		if (j<high&&arr[j]<arr[j+1]) 
			j++; 
		if (arr[i]<arr[j])
		{
			arr[i]=arr[j];
			i=j;
			j=2*i;
		}
		else break;
		arr[i]=temp; 
	}

	for (int i=low;i<=high;i++)
	{

		cout <<arr[i]<<"\t";
	}
	cout<<endl;
}
void heap_sort(int arr[],int len)
{
	int temp;
	sift(arr,1,10);
	for (int i=len/2;i>=1;i--) 
		sift(arr,i,len);
	for (int i=len;i>=2;i--)
	{
		temp=arr[1];
		arr[1]=arr[i];
		arr[i]=temp;
		sift(arr,1,i-1);
	}
}
void merge(int arr[],int low,int mid,int high) //区间是arr[low,mid] arr[mid+1,high]
{
	int i=low,j=mid+1,k=0;
	int *r;
	r=(int *)malloc((high-low+1)*sizeof(int)); //别忘了 free 记得以后用new
	if (!r) exit(0);
	while(i<=mid&&j<=high)
	{
		if (arr[i]<arr[j])
		{
			r[k]=arr[i];i++;k++;
		} 
		else
		{
			r[k]=arr[j];j++;k++;
		}
	}
	while(i<=mid) {r[k]=arr[i];i++;k++;}
	while(j<=high) {r[k]=arr[j];j++;k++;} 
	for (int i=low,k=0;i<=high;i++,k++) //少了个等号=,并且错在arr[i]=r[i]
		arr[i]=r[k]; 
	//  [9/20/2013 qingezha] 补上
	free(r);
}
void merge_pass(int arr[],int length,int n)
{
	int i;
	for (i=0;i+2*length-1<n;i+=2*length) 
		merge(arr,i,i+length-1,i+2*length-1);
	if (i+length-1<n) 
		merge(arr,i,i+length-1,n-1);
}
void merge_sort(int arr[],int n)
{
	for (int i=1;i<n;i=2*i)
	{
		merge_pass(arr,i,n);
	}
}

int binary_search( int a[],const int n,const int value ) /*二分查找*/
{
	int low=0,high=n-1;
	int mid=0;
	if(a != NULL)
	{
		while(low<=high)
		{
			mid=(low+high)/2;//注意可能溢出 low + (high-low)/2
			if (a[mid]==value)
				return mid;
			else if (a[mid]<value) 
				low=mid+1;
			else if(a[mid]>value)
				high=mid-1;
		}
	}
	return -1;
}

//  [9/20/2013 qingezha] 递归 归并排序
//	[start,mid] 和 [mid+1,end] 这两段归并
void merges(int *a,int start,int mid,int end)
{
	if(a == NULL || start <0 || mid<0 || end<0) return;

	int lengh1 = mid - start + 1;
	int lengh2 = end - mid;

	int *left = new int[lengh1];
	int *right = new int[lengh2];

	for(int i=0;i<lengh1;++i)
	{
		left[i] = a[start + i];
	}  
	for (int i=0;i<lengh2;++i)
	{
		right[i] = a[mid + 1 + i];
	}

	int index1=0;
	int index2=0; 

	while(index1<lengh1&&index2<lengh2)
	{
		if(left[index1]>=right[index2])
		{
			a[start++]=right[index2++]; 
		}
		else
		{
			a[start++]=left[index1++]; 
		}
	} 
	while(index1<lengh1)
	{
		a[start++]=left[index1++]; 
	}
	while(index2<lengh2)
	{
		a[start++]=right[index2++]; 
	}
	delete [] left;
	delete [] right; 
}
//  [9/20/2013 qingezha] [start,end] 归并
void merges_sort(int *a,int start,int end)
{
	if(start<end)
	{
		int mid=(end+start)/2;
		merges_sort(a,start,mid);
		merges_sort(a,mid+1,end);
		merges(a,start,mid,end);
	}

}
void CreatBtree(treePtr &b,char strs[])//叶子节点不进入堆栈
{
	BTNode *p,*st[20];
	int j=0,top=-1,k=0,i=-1;
	while(strs[j]!='\0')
	{
		switch (strs[j])
		{
			case '(': k=1;  top++;st[top]=p; break;//在这里进栈
			case ',': k=2;  break;
			case ')':top--; break;
			default:
					{
						p=(BTNode *)malloc(sizeof(BTNode));
						if (!p) exit(0); 
						p->ch=strs[j];p->lchild=NULL;p->rchild=NULL;
						if (b==NULL)
						{
							b=p;k=0;
						} 
						switch (k)
						{
						case 1:st[top]->lchild=p; break;
						case 2:st[top]->rchild=p; break;	
						}
					}
		}
		j++;
	}
}
void ShowBtree(treePtr &p)//显示二叉树元素//主要还是思考不全面!!!这是最大的忌讳!!!!!!!!!
{ 
	if (p!=NULL)
	{
		cout<<p->ch;
		if (p->lchild!=NULL||p->rchild!=NULL)//如果这里不加判断,对于A(B(D(G)),C(E,F));这种情况,当循环到G点时
		{															//由于G点是叶子结点,if(p!=null)通过,但是同时也输出了'(',')'
			cout<<'(';												//这样结果就多了与叶子数,相同的括号的对数
			ShowBtree(p->lchild);							//以后遇到这种情况直接举例说明,临界条件,0,边界,特殊情况
			if(p->rchild!=NULL) cout<<',';
			ShowBtree(p->rchild);
			cout<<')';
		}
	}
}

void PreOrder(treePtr p)//先序读取二叉树元素    //返回为void 的都可以直接判断 p!=null 但是返回int 就要挨个判断了
{
	if (p!=NULL)
	{
		cout<<p->ch;
		PreOrder(p->lchild);
		PreOrder(p->rchild);
	}
}

void MidOrder(treePtr p)//中序读取
{
	if (p!=NULL)
	{
		MidOrder(p->lchild);
		//将二叉查找树转换成双向链表,不能创建任何新的结点,只调正指针方向
		cout<<p->ch;
		//将这个地方换成接口void ConverToDoublelist(treePtr p)
		MidOrder(p->rchild);
	}
	else 
		return;
}

void ConverToDoublelist(treePtr pCurrent)//这种需要使用上一次的参数,需要先把上一次的保留下来
{
	pCurrent->lchild = plist; // 2 ,因为有了上次保存的结点plist 
	if (NULL != plist)        // 3
	{
		plist->rchild = pCurrent;  
	} 
	else
	{
		pHead = plist;
	}
	plist = pCurrent;//第一步写这个 1  因为你下一次调用你还得用上一次的pCurrent
}

void PostOrder(treePtr p)//后序读取
{
	if (p!=NULL)
	{
		PostOrder(p->lchild);
		PostOrder(p->rchild);
		cout<<p->ch;
	}
	else 
		return;
}
void DispLeafs(treePtr p)//显示所有叶子
{
	if (p!=NULL) 
	{
		if (p->lchild==NULL&&p->rchild==NULL)
			cout<<p->ch;//注意了,别把下面的2行也写到if的语句里了//注意循环
		
		DispLeafs(p->rchild);
		DispLeafs(p->lchild);
	}
}


/************************************************************************/
/*
如果根为空,返回0;//递归定义
	如果根元素为ch,那么返回根所在的层次;
		如果根的元素不是ch,那么递归寻找左子树,修改层次值
		如果没有找到,那么递归寻找右子树,修改层次值
*/
/************************************************************************/

int Level(treePtr p,char ch,int h)//求出一个二叉树成员ch,在二叉树的层次
{
	int cout;
	if (p==NULL)
	{
		return 0; //不存在ch
	}
	else
	{
		if (p->ch==ch)//不能和求树的高度混淆了
		{
			return h;
		}
		else
		{
			cout=Level(p->lchild,ch,h+1);//这里特别巧,我还以为要多线程处理,不然h值不唯一
			if (cout==0)							  //每遍历一次数字加一次
			{
				return	Level(p->rchild,ch,h+1);
			}
		}
	}
}
/************************************************************************/
/*
如果根为空,那么返回0;//同样递归定义
	如果根不空,求左子树的高度;
					   求右子树的高度;
	取高度的较大值,即为树的高度;
*/
/************************************************************************/ 
int BtreeHeight(treePtr p)//返回树的高度
{
	int le,ri;
	if (p==NULL)//又一次将==写成了=;这是一个大忌!!!!!!!
	{
		return 0;
	}
	else
	{
		le=BtreeHeight(p->lchild);
		ri=BtreeHeight(p->rchild);
		return (le>=ri)?(le+1):(ri+1);
	}
}

int BtreeLike(treePtr p,treePtr q)//判断2颗数是否相似,即外形一样,数据可以不一样
{
	int left,right;
	if (p==NULL&q==NULL)
	{
		return 1;
	} 
	else if (p==NULL ||q==NULL)
	{
		return 0;
	}
	else 
	{
		left  =BtreeLike(p->lchild,q->lchild);
		right=BtreeLike(p->rchild,q->rchild);//可以这样考虑,假设右子树为空,即返回right==1;
		return left & right;								//然后left与之相与
	}
	
}
  
int FindParents(treePtr p,char ch)//查找节点值为ch的所有祖先,我还以为用队列来存储,
{														//没想到这么做,还是递归!!
	treePtr q;
	if (p==NULL)
	{
		return 0;
	} 
	else if (p->ch==ch)
	{
		return 1;
	}
	else if(FindParents(p->lchild,ch)||FindParents(p->rchild,ch))
	{
		cout<<p->ch<<" ";
		return 1;//这里很关键,递归一定要注意了,要有出口,别忘了写
	} 
}

void PreOrder1(treePtr p)//先序,不用递归
{
	struct
	{
		treePtr q;//访问的结点
		int flag;//标志位,1代表不可访问,0代表可以访问
	}st[20];
	treePtr mid;
	int top=-1;
	top++;st[top].q=p;st[top].flag=1;//根进栈
	while(top>-1)
	{
		mid=st[top].q;top--;//根出栈,因为是先序遍历//这里也可以加条件与中序,后序读取一样
		if (mid!=NULL)			//但是这里不必要,先读根,因为根在堆栈的顶上
		{ 
			top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
			top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
			top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取根,然后左孩子,最后右孩子
		}
		if(st[top].flag==0)
		{
			cout<<st[top].q->ch<<" ";
			top--;
		}
	}
}

void MidOrder1(treePtr p)//中序,不用递归,即左,根 ,右顺序读取
{
	struct
	{
		treePtr q;//访问的结点
		int flag;//标志位,1代表不可访问,0代表可以访问
	}st[20];
	treePtr mid;
	int top=-1;
	top++;st[top].q=p;st[top].flag=1;//根进栈
	while(top>-1)
	{
		if(st[top].flag==1)
		{
			mid=st[top].q;top--;//根出栈,因为是中序遍历,注意这里mid,弹出来又进去,主要变化的是flag从1到0
			if (mid!=NULL)
			{ 
				top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
				top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取左孩子,根,最后右孩子
																			//如果不把mid的flag赋值为0,那么将一直读不出数据
				top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
			}
		}
		if(st[top].flag==0)
		{
			cout<<st[top].q->ch<<" ";
			top--;
		}
	}
}
void PostOrder1(treePtr p)//后序,不用递归,左 右 根 顺序读取
{
	struct
	{
		treePtr q;//访问的结点
		int flag;//标志位,1代表不可访问,0代表可以访问
	}st[20];
	treePtr mid;
	int top=-1;
	top++;st[top].q=p;st[top].flag=1;//根进栈
	while(top>-1)
	{
		if (st[top].flag==1)
		{
			mid=st[top].q;top--;//根出栈,因为序遍历
			if (mid!=NULL)
			{ 
				top++;st[top].q=mid;st[top].flag=0;//根进栈,后进先出,先读取根,然后左孩子,最后右孩子
				top++;st[top].q=mid->rchild;st[top].flag=1;//右孩子进栈
				top++;st[top].q=mid->lchild;st[top].flag=1;//左孩子进栈
			}
		} 
		if(st[top].flag==0)
		{
			cout<<st[top].q->ch<<" ";
			top--;
		}
	}
}
//  [10/11/2013 qingezha]  完全二叉树第m层第k个节点 都是从0开始 那么保存在数组里面从0开始,到2的m次方+k-1即可得到那个元素
void LeavelOrder(treePtr p)//分层读取,与队列很相像,先读的先入队,从头出队,front==rear循环终止条件
{
	const int Maxsize=20;
	int front,rear;front=rear=-1;
	treePtr qu[Maxsize],q;//Maxsize 可以调整,这里用环形队列,节约资源,
	rear=rear+1;qu[rear]=p;//头指针入队列
	while(front!=rear)//这里很关键,front 和 rear 指针,环形的,出队 入队相结合
	{
		front=front+1;//这里别忘了%Maxsize
		q=qu[front];//出队列
		cout<<q->ch<<" ";
		if (q->lchild!=NULL)
		{
			rear=(rear+1)%Maxsize;//先读取左指针,先入队列,先入队列的先出队列
			qu[rear]=q->lchild;
		}
		if (q->rchild!=NULL)
		{
			rear=(rear+1)%Maxsize;//后读取右指针,后入队列。符合按层次读取思想
			qu[rear]=q->rchild;
		}
	}
}
treePtr CreatBT1(char *pre,char *mid,int n)//pre先序头指针,mid中序指针,n为结点个数
{																	  //pre指针的第一个元素为根元素
	treePtr s,temp;
	char *p=mid;
	int k=0,m;
	if(n<=0) return NULL;//这里很关键,递归出口
	s=(treePtr)malloc(sizeof(BTNode));if (!s) exit(0);
	s->ch=*pre;
	while(k<n)
	{
		if (*(p+k)==*pre) 
			break;
		k++;
	} 
	s->lchild=CreatBT1(pre+1,mid,k);//k为左子树的结点个数,n-k+1为柚子树个数,要出去根元素,所以减1
	s->rchild=CreatBT1(pre+k+1,mid+k+1,n-k-1);//调整头指针
	return s;
}
treePtr CreatBT2(char *post,char *mid,int n)//post后序指针,mid中序指针,n为结点个数
{																		//post指针的最后一个元素为根元素
	treePtr s;
	char *p=mid;
	int k=0;
	if (n<=0) return NULL;
	s=(treePtr)malloc(sizeof(BTNode));if (!s) exit(0);
	s->ch=*(post+n-1);
	while(k<n)
	{
		if(*(p+k)==s->ch)
			break;
		k++;
	}
	s->lchild=CreatBT2(post,mid,k);//这样将mid分成了两部分,以根元素为分点,分为左右子树
	s->rchild=CreatBT2(post+k,mid+k+1,n-k-1);//左右子树,mid 和mid +k +1,post +k
	return s;
}
void dijkstra(int v,float adj[][VERTEX_COUNT],float dist[],int prev[])
{
	bool s[VERTEX_COUNT]={false};
	for (int i=1;i<VERTEX_COUNT;++i)		//初始化 prev dist,后面需要使用
	{
		dist[i] = adj[v][i];
		s[i] = false;
		if(dist[i] != FLT_MAX) 
			prev[i] = v;					//表示前驱为 源点
		else
			prev[i] = -1;					//表示 无前驱
	}
	s[v] = true;
	dist[v] = 0;
	for (int i=1;i<VERTEX_COUNT;++i)
	{
		float temp = FLT_MAX;
		int u = v;
		for (int j=1;j<VERTEX_COUNT;++j)	//选出最短路径加入集合
		{
			if(!s[j] && dist[j]<temp)
			{
				temp = dist[i];
				u = j;
			}
		}
		s[u] = true;						//加入集合
		int newdist = 0;					
		for (int j=1;j<VERTEX_COUNT;++j)	//调正dist[],这些值是只经过s中的点,现在s变化了,所以dist也协同变化
		{
			if (!s[j] && adj[u][j] != FLT_MAX)
			{
				newdist = dist[u] + adj[u][j];//很重要的一点,更新dist,只要根据新加入的点 u 来计算,因为以前的点已经计算过了
				if(newdist < dist[j])
				{
					dist[j] = newdist;
					prev[j] = u;
				}
			}
		}
	}


	//test
	float dist[VERTEX_COUNT]={0.0};
	int prev[VERTEX_COUNT] = {0};
	float adj[VERTEX_COUNT][VERTEX_COUNT] = {{0,10,FLT_MAX,30,100},{FLT_MAX,0,50,FLT_MAX,FLT_MAX},
	{FLT_MAX,FLT_MAX,0,FLT_MAX,10},{FLT_MAX,FLT_MAX,20,0,60},{FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX,0}};
	dijkstra(0,adj,dist,prev);
	for(int i=0;i<VERTEX_COUNT;++i)
	{
		cout<<i+1<<" "<<dist[i]<<"("<<prev[i]+1<<")"<<endl;
	}
	//
}
void GetNext(Sqstring t,int next[])//获得一个字符串的next数组
{														//如a b  c  a b c d a e b
	int j=0,k=-1;								//  -1 0  0 0 1 2 3 0 1 0 //即此下标之前匹配的字符个数,默认第0个为-1,1个为0
	next[0]=-1;
	while(j<t.len-1)
	{
		if (k==-1||t.data[j]==t.data[k])
		{
			k++;j++;next[j]=k;
		}
		else
		{
			k=next[k];//j+1位置对应要移动的位置
		}
	}
}
int KMPIndex(Sqstring s,Sqstring t)//s为主串,t为目标串
{
	int i=0,j=0,next[10]={0};
	GetNext(t,next);
	while(i<s.len&&j<t.len)
	{
		if (j==-1||s.data[i]==t.data[j])//j==-1 1从t头开始匹配,即没有找到pk与pj相同,从头在一一匹配
		{
			++i;++j;
		}
		else
		{
			j=next[j];
		} 
	}
	if (j>=t.len)
	{
		return i-t.len;
	}
	else
		return -1;
}
struct {int i,j;//迷宫的位置
int pre;//迷宫上一块在队列的位置
}qu[50];
int front=-1,rear=-1;//队列头尾节点
//迷宫 堆栈求解,不能求出最优解
int mgpath(int x1,int y1,int x2,int y2)
{
	int top=0,i,j,di,find=0;//find 表示是否找到下一个位置(1是)
	st[top].i=x1;st[top].j=y1;st[top].di=-1;mg[x1][y1]=-1;//防止重复走一个点,走过的用 -1 标记
	while(top>-1)
	{
		find=0;
		i=st[top].i;j=st[top].j;di=st[top].di;
		if (i==x2&&j==y2)
		{
			for (int k=0;k<=top;k++)
			{ 
				mg[st[k].i][st[k].j]=5; 
			}
			for (int g=0;g<10;g++)
			{
				for (int k=0;k<10;k++)
				{
					cout<<mg[g][k]<<"   ";
				}
				cout<<"\n";
			}
			cout<<"成功找到一条路";
			return 1;
		}
		while(di<4&&find==0)//一次找到一个就可以,然后跳出循环
		{
			di++;
			switch (di)
			{
			case 0:i=st[top].i-1;j=st[top].j;break;//因为i,j,是全局变量,很容易被改变,还是用st[top]赋值很放心
			case 1:j=st[top].j+1;i=st[top].i;break;
			case 2:i=st[top].i+1;j=st[top].j;break;
			case 3:j=st[top].j-1;i=st[top].i;break;
			}
			if(mg[i][j]==0) find=1;
		}
		if (find==1)
		{
			st[top].di=di;top++;st[top].i=i;st[top].j=j;st[top].di=-1;mg[i][j]=-1;
		}
		else
		{
			mg[st[top].i][st[top].j]=0;top--;
		}
	}
} 
//迷宫 队列求解,可以求出最优解
int mgpath2(int x1,int y1,int x2,int y2)
{
	int find=0,i,j;
	rear++;qu[rear].i=x1;qu[rear].j=y1;qu[rear].pre=-1;mg[x1][y1]=-1;//加入队列的将mg致1,
	while(front<=rear&&find==0)
	{
		front++;i=qu[front].i;j=qu[front].j;
		if (i==x2&&j==y2)
		{
			int k,sum=front;
			find=1;
			do 
			{
				k=qu[front].pre;
				qu[front].pre=-1;
				front=k;
			} while (k!=0);
			k=0;
			while(k<=sum)
			{
				if(qu[k].pre==-1)
					cout<<qu[k].i<<" "<<qu[k].j<<endl;
				k++;
			}
			return find;
		}
		for (int di=0;di<4;di++)
		{
			switch (di)
			{
			case 0:i=qu[front].i-1; j=qu[front].j;break;//因为i,j,是全局变量,很容易被改变,还是用st[top]赋值很放心
			case 1:j=qu[front].j+1;i=qu[front].i;break;
			case 2:i=qu[front].i+1;j=qu[front].j;break;
			case 3:j=qu[front].j-1; i=qu[front].i;break;
			}
			if(mg[i][j]==0)
			{
				rear++;
				qu[rear].i=i;qu[rear].j=j;qu[rear].pre=front;mg[i][j]=-1;
			}
		}
	}
	return find;
}

#include "beauty_of_programming.h"
#include <iostream>
#include <assert.h>
#include <list>
#include <vector>
using namespace std; 
//中国象棋将帅问题,A B 所有合法位置,只能使用一个字节存储变量 1.2
void General()
{
	struct 
	{
		unsigned char a:4;//在结构体里 a 在8位中的0-3
		unsigned char b:4;//b 在4-7,输出时要进行强制转换
	} i;
	for(i.a=1;i.a<=9;i.a++)
		for(i.b=1;i.b<=9;i.b++)
		{
			if(i.a%3!=i.b%3)
				cout<<(int)i.a<<"\t"<<(int)i.b<<endl;//记住这里需要显示的强制转换
		}
}

int max(int a,int b)
{

	return (a>b)?a:b;
}

int MaxSum(int *a,int n)
{
	int start=a[n-1];
	int all=a[n-1];
	for (int i=n-2;i>=0;i--)
	{
		start=max(a[i],start+a[i]);//包含a[i]的最大值 ,a[i]后面一段的最大值
		all=max(start,all);//
	}
	return all;
}
 
int MaxSum2( int *a,int size ) /*数据结构:思想与实现 P14 当检测到一负序列,表示该子序列不可能包含在最大子序列中 */
{							//该算法只适用于序列里面有正有负的情况,全部为负就不行了,全部为负的话,就直接取一个最大值
	int thismax=0;
	int maxx=0;
	int end=0,start=0;
	for (int i=0;i<size;i++)
	{
		thismax+=a[i];
		if (thismax>maxx)
		{
			maxx=thismax;
			end=i;
		} 
		else
		{
			if (thismax<0)
			{
				thismax=0;
				start=i+1;
			}
		}
	}
	return maxx;
}

int MaxSum3(int *arr, int lengths) //这个适用于有正有负的数组,全是负的不行!!!
{
	int sums= 0;
	int next = 0;
	for (int i = 0;i < lengths; ++i)
	{
		if(next <= 0)			//连续子数组和小于0,则用下一个元素替代这个字数组和
			next = arr[i];		//如果字数组和大于sum,则替代之
		else
			next += arr[i];
		if(sums < next)
			sums = next;
	}
	return sums;
}
//  [10/7/2013 qingezha] 给你一个数组,有正有负,返回最大的连续项的乘积
//	如果数组遇到0 则乘积为0,0 和 负数 都比任何一个正数小,那么这种情况下只要取一个最大的连续乘积的正值就可以了
double max_multi_arr(double *arr,int len)
{
	if(arr == NULL || len<=0) 
		return 0.0;
	double temp = 1.0;
	double sums = arr[0];
	for (int i=0;i<len;++i)
	{
		if(arr[i]!=0)				//元素与0 比较
		{
			temp *= arr[i];
			if(temp>sums)
				sums = temp;
		}
		else
		{
			if(temp>0 && temp>sums)
				sums =temp;
			temp = 1;				//别忘了置0
		}
	}
	return sums;
}
int Cal() /*T=7 */
{
	const int INF=-10000;
	const int V=64;
	const int T=7;
	int x=0;
	//opt[v][i]表示在第i,i+1,i+2...T-1种饮料中,总容量为v的满意度之和的最大值
	int opt[V+1][T+1]={};//购买总容量为V的T类饮料的满意度,
	int C[T]={3,2,1,3,2,4,1};//10种饮料,每种饮料的数量的最大值
	int v[T]={2,4,8,2,4,8,16};//10中饮料,每种饮料的容积
	int H[T]={20,30,25,30,15,30,100};//每种饮料的满意度
	for (int i=1;i<=V;i++)
	{
		opt[i][T]=INF;
	}
	opt[0][T]=0;
	for (int j=T-1;j>=0;j--) 
	{
		for (int i=0;i<=V;i++)
		{
			opt[i][j]=INF;
			for (int k=0;k<=C[j];k++)
			{
				if(i<k*v[j]) break;
				x=opt[i-k*v[j]][j+1];
				if (x!=INF)
				{
					x+=H[j]*k;
					if (x>opt[i][j])
					{
						opt[i][j]=x;
					}
				}
			}
		}
	}
	return opt[V][0];
}

int ElevatorMin()
{
	int nperson[11];//共10层,要到 i 层的人数是 nperson[i]
	int N1=0;
	int N2=nperson[1];
	int N3=0;
	int minFloors=0;
	int targetFloor=1;
	for (int i=2;i<11;i++)
	{
		N3+=nperson[i];//第2层到10层的人数
		minFloors+=nperson[i]*(i-1);//要到第2层与第10层的人从1楼到各自楼层所爬的总的层数
	}
	for (int i=2;i<11;i++)
	{
		if (N1+N2<N3)
		{
			minFloors+=N1+N2-N3;
			targetFloor=i;
			N1+=N2;
			N2=nperson[i];
			N3-=N2;
		}
		else
			break;
	}
	return targetFloor;
}

char Find( char *p,int n )
{
	int times=0;
	char targetch=' ';
	for (int i=0;i<n;i++)
	{
		if (times==0)
		{
			targetch=p[i];//记录当前猜测水王的ID
			++times;			//记录水王ID出现的次数
		} 
		else
		{
			if(targetch==p[i])//如果相同则次数加一
				++times;
			else
				--times;//不同则次数减一,即同时删除这2个不同的ID
		}
	}
	return targetch;
}

int* MaxLen( int *a,const int n)  //最长递增子序列的长度 ,没有要求是连续的!!!!!!
{
	int len=1;
 	int lenx=1; 
	int *Lists=new int[n]; 
	for (int i=0;i<n;i++)
	{
		Lists[i]=1;len=1;
		for (int j=0;j<i;j++)
		{ 
			if(a[i]>a[j]) // if(a[i]>a[j] && lists[j]+1>list[i]) lists[i]=lists[j]+1;
			{
				len=Lists[j];
				len++;
			}
			if(len>Lists[i])
			{
					Lists[i]=len; 
			}
		}
	} 
	return Lists;
}
//  [7/1/2013 qingezha] 找出一个数组中的第二大数,遍历一遍
int Find_Sec_Max( int *a,int n ) 
{
	const int INF=-32767;
	int maxnum=a[0];
	int secmax=INF;
	int temp = 0;
	for (int i=1;i<n;i++)
	{
		/*if (a[i]>maxnum)    //方法1
		{
			secmax=maxnum;
			maxnum=a[i];
		} 
		else if(a[i]>secmax)
		{
			secmax=a[i];
		}*/
		if (maxnum<a[i])		//方法2
		{
			temp = maxnum;
			maxnum = a[i];
		}
		if(temp>secmax)
			secmax = temp;
	}
	cout<<"this second maxnum is "<<secmax<<endl;
	return secmax;
}

LinkPtr hasCricularLink( LinkPtr & p )//判断有无环,快慢指针,走一步,走两步,相遇,可以求得相遇点
{									//一个从相遇点,另一个从头结点出发,速度一样,相遇的第一点为
	LinkPtr slow,fast;				//即为环的初始点
	fast=slow=p;
	if (!p||!fast)  return NULL;
	while(NULL!=slow)
	{
		if(NULL==fast->next) return NULL;		//如果有环则把环的,则把
		fast=fast->next->next;
		slow=slow->next;
		if(slow==fast) return slow;
	}
}
//  [10/10/2013 qingezha]寻找上亿数据TOP K
void FindKMax()
{
	//for(long i=0;i<1000;i++)
	//{
	//	ofstream outFile; //输出到外存 
	//	outFile.open("D:\\t.txt",ios_base::app);
	//	srand(i);
	//	long s=rand()<<6;
	//	outFile<<s<<" ";
	//	outFile.close(); 
	//}
	//
	//system("pause");
	// 定义数组存储堆元素  
	int k;  
	cin >> k;  
	long *heap = new long [k+1];   //注,只需申请存储k个数的数组  
	FILE *fp = fopen("D:\\t.txt", "r"); //从文件导入海量数据(便于测试,只截取了9M的数据大小)  
	assert(fp);  

	for (int i = 1; i <= k; i++)  
		fscanf(fp, "%d ", &heap[i]);  
	for (int j = 1; j <= k; j++)  
		cout << heap[j] << " ";  
	cout << endl;  
	for (int i=k/2+1;i>=1;--i)
	{
		siftMaxx(heap,i,k);
	}  
	for (int j = 1; j <= k; j++)  
		cout << heap[j] << " ";  
	cout << endl;  
	long newData;  
	while (fscanf(fp, "%d", &newData) != EOF)  
	{   
		if (newData > heap[1])   //找最小的K个数 如果遇到比堆顶元素kmax更小的,则更新大堆,  
		{											//找最大的K数,更新小堆
			heap[1] = newData;  
			siftMaxx(heap,1,k); //调整堆  
			for (int j = 1; j <= k; j++)  
				cout << heap[j] << " ";  
			cout << endl;  
		}  

	}  

	for (int j = 1; j <= k; j++)  
		cout << heap[j] << " ";  
	cout << endl;  

	fclose(fp); 
	system("pause");

}
void siftMaxx( long arr[],int low,int high ) /*区间[low,high],构造二叉堆//大的到根部去,小的到叶子去*/
{
	// 这两中方法都可以 ,但是推荐第二种
	int i=low;
	int j=2*i;
	int temp=arr[i];
	while(j<=high)
	{
		if (j<high&&arr[j]>arr[j+1]) 
			j++; 
		if (arr[i]>arr[j])
		{
			arr[i]=arr[j];
			i=j;
			j=2*i;
		}
		else break;
		arr[i]=temp; 
	}

	//
	int child;
	for (int i=1;i<high;i=child)
	{
		child=2*i;
		if (child+1<=high&&arr[child]>arr[child+1]) 
			++child;
		if(arr[child]<arr[i])  //检查是否越界,很多时候的bug最后检查出来都是小毛病,但是浪费了很多时间
										//if(child<=high&&arr[child]<arr[i]) 这样就对了
			swap(arr[child],arr[i]);
	}
}

ptr_has_space head[HASHLEN];//不能在头文件中定义

void write_to_file()//将hash后的结果保存在result.txt中
{
	FILE *fp = fopen("D:\\result.txt", "w");  
	assert(fp);   
	int i = 0;  
	while (i < HASHLEN)  
	{  
		for (ptr_has_space p = head[i]; p != NULL; p = p->next)  
			fprintf(fp, "%d  %d\n", p->data, p->count);  
		i++;  
	}  
	fclose(fp);
}

void append_hash( const int *p )//附加到hash表中,如果重叠则链表表示
{
	int index=hash_function(p);
	ptr_has_space q=head[index];
	if(NULL==q)
	{
		head[index]=new node_has_space;
		head[index]->count=1;
		head[index]->data=*p;
		head[index]->next=NULL;
		return;
	}
	else
	{
		while(q)
		{
			if(*p==q->data)
			{
				++(q->count);
				return;
			}
			q=q->next;
		}
		ptr_has_space pt=new node_has_space;
		pt->count=1;pt->data=*p;
		pt->next=head[index];//采用头插入法
		head[index]=pt;
	}
}

int hash_function( const int * p )//简单hash函数
{
	int index=0;
	if(*p>HASHLEN) 
		index=*p%HASHLEN;
	else
		index=*p;
	return index;
}
 

void siftheap( node_has_space arr[],int low,int high )//堆结点类型为node_has_space,筛选
{
	int i=low;
	int j=2*i;
	node_has_space temp=arr[i];
	while(j<=high)
	{
		if (j<high&&arr[j].count>arr[j+1].count) 
			j++; 
		if (arr[i].count>arr[j].count)
		{
			arr[i]=arr[j];
			i=j;
			j=2*i;
		}
		else break;
		arr[i]=temp; 
	}
	 
}

void bigDATASearch()
{
	//写进数据,模拟上亿的数据
	//for(long i=0;i<100000;i++)
	//{
	//	ofstream outFile; //输出到外存 
	//	outFile.open("D:\\t.txt",ios_base::app);
	//	srand(i);
	//	long s=rand()%30000;
	//	outFile<<s<<" ";
	//	outFile.close(); 
	//}
	//
	//system("pause");

	//将上亿的数据归类,hash,记录重复的次数,然后以<key  count> \n 形式写进txt里面
	//int *dataptr=new int;
	//FILE *fp = fopen("D:\\t.txt", "r");   //从文件导入海量数据 
	//assert(fp); 
	//while(fscanf(fp,"%d",dataptr)!=EOF)
	//{
	//	append_hash(dataptr);
	//}
	//fclose(fp); 
	//write_to_file();
	//system("pause");

	//读取上述txt,用堆的形式取前K个count最大值
	int k;  
	cin >> k;  
	ptr_has_space  heap = new node_has_space[k+1];   //注,只需申请存储k个数的数组  
	FILE *fp = fopen("D:\\result.txt", "r");   //从文件导入海量数据(便于测试,只截取了9M的数据大小)  
	assert(fp);  

	for (int i = 1; i <= k; i++)  
		fscanf(fp, "%d %d", &(heap[i].data),&(heap[i].count));   
	for (int i=k/2+1;i>=1;--i)
	{
		siftheap(heap,i,k);
	} 
	for (int j = 1; j <= k; j++)  
		cout << heap[j].data<<" "<<heap[j].count << " ";  
	cout << endl;  
	long newData;
	int count;
	while (fscanf(fp, "%d %d", &newData,&count) != EOF)  
	{   
		if (count > heap[1].count)   //找最小的K个数 如果遇到比堆顶元素kmax更小的,则更新大堆,  
		{											//找最大的K数,更新小堆
			heap[1].data = newData;  
			heap[1].count=count;
			siftheap(heap,1,k); //调整堆  
			for (int j = 1; j <= k; j++)  
				cout << heap[j].data << "\t"<<heap[j].count<<"\t";  
			cout << endl;  
		}   
	}  

	for (int j = 1; j <= k; j++)  
		cout << heap[j].data << " "<<heap[j].count;  
	cout << endl;  

	fclose(fp); 
	system("pause");
}



bool Young( int arr[ROW][COL],int value ) /*找到返回true,否则返回false;*///若小则向下找,若大则向左找
{
	int i=0,j=COL-1;
	int temp=arr[i][j];
	while(1)
	{
		if (value==temp)
			return true;
		else if(value>temp&&i+1<ROW) 
			temp=arr[++i][j];
		else if(value<temp&&j>0)
			temp=arr[i][--j];
		else return false;
	}

	//测试函数
	int arrr[4][4]={{1 ,2 ,8, 9},{2,4,9,12},{4,7,10,13},{6,8,11,15}};
	bool res=false;
	for (int i=1;i<=15;i++)
	{
		cout<<i<<" ";
		res=Young(arrr,i);
		if(res) cout<<"exist"<<endl;
		else cout<<"not exist"<<endl;
	}

}


void trace_Back( int i,int j,int m[][N+1])
{
	if(i==j) return; 
	trace_Back(i,m[i][j],m);
	trace_Back(m[i][j]+1,j,m);
	cout<<"A"<<i<<","<<m[i][j]<<"A"<<(m[i][j]+1)<<","<<j<<endl;
}
//  [9/15/2013 qingezha]先求出A1*A2 A2*A3 A3*A4 ...	然后3个连乘积,4个连乘积。。。
void matrix_Chain(const int p[N+1],int m[][N+1],int s[][N+1])
{																				                     //然后求出A1*A2*A3  A2*A3*A4...这利用了A1*A2 ,A2*A3
	for(int i =1;i<=N;++i) m[i][i]=0;//自身的乘积次数为0
	for (int r=2;r<=N;r++)//连续的r个矩阵相乘
	{ 
		for (int i=1;i<=N-r+1;i++)//i的界限A1*A2*A3 A2*A3*A4...A6*A7*A8,i为1到6,当4个矩阵连乘积是i从1到5
		{														//从而可以知道i的最大值N-r+1
		    int j=i+r-1;
			m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];        //如果A为m行*n列,B为n行*l列,那么A*B,总共需要乘积的次数为m*n*l
			s[i][j]=i;													//从i相连的求得的最小值,如s[1][6]为3,则m[1][6]=m[1][3]+m[4][6],这样递归
			for (int k=i+1;k<j;k++)
			{
				int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
				if (m[i][j]>temp)
				{
					m[i][j]=temp;//m[i][j] 即Ai*Ai+1*Ai+2...Aj的总的乘积的次数
					s[i][j]=k;//记住最小值k,意思是从i到k然后到j,算出来的最小值
				}
			}
		}
	}

	for (int i=1;i<N+1;++i)
	{
		for (int j=1;j<N+1;++j)
		{
			cout<<m[i][j]<<"\t";
		}
		cout<<endl;
	}
	for (int i=1;i<N+1;++i)
	{
		for (int j=1;j<N+1;++j)
		{
			cout<<s[i][j]<<"\t";
		}
		cout<<endl;
	}
	 
	//矩阵乘积测试用例
	int p[7]={30,35,15,5,10,20,25};//共6个矩阵,下标依次是1 2 3 4 5 6
	int m[7][7]={0};
	int s[7][7]={0};
	matrix_Chain(p,m,s);
	trace_Back(1,6,s);
}

int recur_matrix_Chain(int i,int j,const int p[N+1],int s[][N+1])//递归求解m[i][j]
{
	if(i==j) return 0;
	int u=recur_matrix_Chain(i+1,j,p,s)+p[i-1]*p[i]*p[j];
	for (int k=i+1;k<j;k++)
	{
		int temp=recur_matrix_Chain(i,k,p,s)+recur_matrix_Chain(k+1,j,p,s)+p[i-1]*p[k]*p[j];
		if(temp<u)
		{
			u=temp;
			s[i][j]=k;
		}
	}
	return u;
}
 
int memorized_matrix_Chain(int j,int m[][N+1],const int p[N+1],int s[][N+1])//备忘录求解
{
	for (int i=1;i<=N;i++)
	{
		for(int k=1;k<=N;k++)
			m[i][k]=0;
	}
	return lookupChain(1,j,p,s,m);
}
int lookupChain(int i,int j,const int p[N+1],int s[][N+1],int m[][N+1])
{
	if (0!=m[i][j])  return m[i][j];//每次查询备忘录,若已经计算过,则直接返回,不用计算
	if(i==j) return 0;
	int u=lookupChain(i+1,j,p,s,m)+p[i-1]*p[i]*p[j];
	for (int k=i+1;k<j;k++)
	{
		int temp=lookupChain(i,k,p,s,m)+lookupChain(k+1,j,p,s,m)+p[i-1]*p[k]*p[j];
		if(temp<u)
		{
			u=temp;
			s[i][j]=k;
		}
	}
	m[i][j]=u;//写进备忘录里面 
	return u;
	//测试用例
	int pp[7]={30,35,15,5,10,20,25};//共6个矩阵,下标依次是1 2 3 4 5 6
	int mm[7][7]={0};
	int ss[7][7]={0}; 

	cout<<memorized_matrix_Chain(6,mm,pp,ss);
}


int Catalan(int n)  //卡特兰数 Cn=(1/n+1)(2n,n),(2n,n)为组合数h(0)=1;h(1)=1
{  
	if(n <= 1)		
		return 1;   
	int *h = new int [n+1]; //保存临时结果  
	h[0] = h[1] = 1;        //h(0)和h(1)  
	for(int i = 2; i <= n; i++)    //依次计算h(2),h(3)...h(n)  
	{  
		h[i] = 0;  
		for(int j = 0; j < i; j++) //根据递归式计算 h(i)= h(0)*h(i-1)+h(1)*h(i-2) + ... + h(i-1)h(0)  
			h[i] += (h[j] * h[i-1-j]);  
	}  
	int result = h[n]; //保存结果  
	delete [] h;       //注意释放空间  
	return result;  
}  

//  [7/7/2013 qingezha] 递归的产生全排列  暂时没弄懂原理
//  [9/13/2013 qingezha] 现在已经弄懂了,知道怎么写了,哈哈哈
//	这个接口很重要,对数组arr 下标为k和m之间的元素全排列,思路是这样的:
//	1 递归出口为 k = m 时说明一个全排列已经排好 
//	2 从 k 到 m 循环,依次将第一个字符与后面的每一个字符交换,然后全排列后面(k+1,m),然后将交换后的在交换回来,接着交换下一个
void perm(int arr[],int k,int m)
{
	if (k==m)			//需要判断指针与m,k,提高健壮性
	{
		for (int i=0;i<m;++i)
		{
			cout<<arr[i]<<"\t";
		} 
	}
	else
	{
		for(int i=k;i<m;++i)		//如1 2 3 4 ;1 和 1 交换,全排列2 3 4
		{
			swap(arr[k],arr[i]);	//交换第k个和从k开始到末尾
			perm(arr,k+1,m);		//交换后全排列后面的
			swap(arr[k],arr[i]);
		}
	}
}
//  [9/13/2013 qingezha] 整数划分问题,比如整数 6 可以划分多少种不同 正整数 相加的情况 //算法设计 王晓东
//	比如和为 n ,最大加数因子为 m ,这样q(n,m)代表划分的种类数,
//	q(n,1) = 1,q(1,m) = 1,q(n,n) = q(n,n-1)+1, q(n,m) = q(n,n)(m>n),
//	q(n,m)=q(n,m-1)+q(n-m,m)这个牛逼公式
int q(int n,int m)
{
	if(n==1||m==1) 
		return 1;
	if(m>n)
		return q(n,n);
	if(m==n)
		return q(n,m-1)+1;
	return q(n,m-1) + q(n-m,m);
}
//  [9/13/2013 qingezha] 汉罗塔问题 比如 n 个盘子在a上,现在要移动到 b 上,c 是辅助,递归的过程是:如果只有一个盘子可以直接从 a 移到 b 
//	如果 n 个,可以先拿 n-1 到 c ,然后将第 n 个移动到 b 中,最后将 n-1 移动到 b 上

 void hanoi(int n, int a, int b,int c)
 {
	 if (n>0)
	 {
		 hanoi(n-1,a,c,b);
		 cout<<"from "<<a<<" to "<<b<<endl;
		 hanoi(n-1,c,b,a);
	 }
 }
//  [7/7/2013 qingezha] 动态规划 最长公共子序列 c[i][j]表示Xi={x1,x2,x3。。。xi}与Yj={y1,y2,。。。yj}的最长公共字串序列的长度
int lcs_length(char x[],char y[],int b[LA+1][LB+1],int c[LA+1][LB+1])
{
 
	for (int i=1;i<=LA;++i)  c[i][0]=0; //数组需要初始化,否则值不一定
	for (int i=1;i<=LB;++i)  c[0][i]=0;
	for (int i=1;i<=LA;++i)
	{
		for (int j=1;j<=LB;++j)
		{
			if (x[i]==y[j])      //序列从1开始计数
			{
				c[i][j]=c[i-1][j-1]+1;//把c[i][j] 写成了c[i][i]了,重大失误,造成4个小时的浪费
				b[i][j]=1;				//b记录c的值由哪一个子问题的解得到的
			} 
			else if(c[i-1][j]>=c[i][j-1])
			{
				c[i][j]=c[i-1][j];
				b[i][j]=2;
			}
			else
			{
				c[i][j]=c[i][j-1];
				b[i][j]=3;
			}
		}
	}
	测试代码//
	for (int i=1;i<=LA;++i)           //可以将数据输出来看看,哪里有不符合逻辑的错误
	{
		for (int j=1;j<=LB;++j)
		{
			cout<<b[i][j];
		}
		cout<<endl;
	}
	cout<<endl;
	for (int i=1;i<=LA;++i)
	{
		for (int j=1;j<=LB;++j)
		{
			cout<<c[i][j];
		}
		cout<<endl;
	}
	cout<<endl;
	 
	char x[7+2]=" abcdefx";
	char y[7+2]=" aecxdfx";
	int b[8][8]={{0}};
	int c[8][8]={{0}};
	int a[8]={0};
	cout<<lcs_length(x,y,b,c)<<endl;
	lcs(7,7,x,b);
	//
	return c[LA][LB];
}

void lcs(int i,int j,char x[],int b[LA+1][LB+1])
{

	if(0==i||0==j) return;
	if (b[i][j]==1)
	{
		lcs(i-1,j-1,x,b);
		cout<<x[i]<<" ";
	}
	else if(2==b[i][j])
		lcs(i-1,j,x,b);
	else lcs(i,j-1,x,b);
}

//  [7/8/2013 qingezha] 0-1背包问题 包可以承受的重量为c,物品的重量为w[n+1]=w[1],w[2]w[3]...w[n]
//物品的价值为v[n+1]=v[1],v[2],...v[n],,
//最优值为m[i][j],背包可以承受的重量为j(当前剩余的空间),可以选择的物品为
//i,i+1,i+2...n时0-1背包问题的最优值
//递归表达式 为
//		m[n][j]=v[n],if(j>=w[n]);or  =0,if(j<w[n])
//		m[i][j]=max(m[i+1][j],m[i+1][j-w[i]])+v[i],if(j>=w[i]); or =m[i+1][j] if(j<w[i])
//v 从1开始记数 w也是从1开始记数 分别表示物品的价值和重量 c表示背包的所承受的总重, m表示最优值
//v[6]=v[0],v[1],...v[5],同理w
int knapsack(int v[KIND+1],int w[KIND+1],int c,int m[KIND+1][ALLWEIGHT+1])
{
	int maxweight=0;
	if(w[KIND]<=c) 
		maxweight=w[KIND];			//最后一个物品重量
	else maxweight=c;
	for (int i=0;i<maxweight;++i)		
		m[KIND][i]=0;				//背包空间 < 最后一个物品的重量
	//m[KIND][i] = (i<maxweight ? 0: v[KIND]); //这样简洁
	for (int i=maxweight;i<=c;++i) 
		m[KIND][i]=v[KIND];
	for (int i=KIND-1;i>=1;--i)
	{
		maxweight=w[i];
		for (int j=0;j<=c;++j)
		{
			if (j<maxweight)
			{
				m[i][j]=m[i+1][j];
			} 
			else
			{
				int m1=m[i+1][j];
				int m2=m[i+1][j-maxweight]+v[i];
				if (m1>=m2)
					m[i][j]=m1;
				else
					m[i][j]=m2;
			}
		}
	}
	 return m[1][ALLWEIGHT];
}
void traceback(int m[KIND+1][ALLWEIGHT+1], int w[KIND+1],int c,int x[])
{
	for (int i=1;i<KIND;++i)
	{
		if(m[i][c]==m[i+1][c])
			x[i]=0;
		else
		{
			x[i]=1;
			c-=w[i];
		}
		x[KIND]=(m[KIND][c]>0)?1:0;
	}


	//test
	int vv[6]={0,7,9,5,4,6};
	int ww[6]={0,9,2,6,5,4};
	int cc=ALLWEIGHT;
	int xx[6]={0};
	int mm[6][ALLWEIGHT+1]={{0}};
	cout<<knapsack(vv,ww,cc,mm)<<endl;
	traceback(mm,ww,cc,xx);
	for (int i=1;i<6;++i)
	{
		cout<<xx[i]<<"\t";
	}

	//void fun0(int a[][2])
	//{
	//	cout<<a[0][0];
	//}
	//void fun1(int (*a)[2])//一个2列的数组,行数不确定,里面存的是int
	//{
	//	cout<<a[0][0];
	//}
	//void fun2(int **a)
	//{
	//	cout<<a[0][0];
	//}
	//void fun3(int *a[]) //int * a  一个数组指针,里面的元素是指向整型的指针
	//{
	//	cout<<a[0][0];
	//}
}
//  [9/16/2013 qingezha]
//	单源最短路径,v为源头,adj为邻接矩阵,其中不属于边集合时设成FLT_MAX,dist为从源头到各个点的距离
//  prev 为 dist 路径上的前一个顶点, 默认 v 为 0 即源点

void dijkstra(int v,float adj[][VERTEX_COUNT],float dist[],int prev[])
{
	bool s[VERTEX_COUNT]={false};
	for (int i=1;i<VERTEX_COUNT;++i)		//初始化 prev dist,后面需要使用
	{
		 dist[i] = adj[v][i];
		 s[i] = false;
		 if(dist[i] != FLT_MAX) 
			 prev[i] = v;					//表示前驱为 源点
		 else
			 prev[i] = -1;					//表示 无前驱
	}
	s[v] = true;
	dist[v] = 0;
	for (int i=1;i<VERTEX_COUNT;++i)
	{
		float temp = FLT_MAX;
		int u = v;
		for (int j=1;j<VERTEX_COUNT;++j)	//选出最短路径加入集合
		{
			if(!s[j] && dist[j]<temp)
			{
				temp = dist[i];
				u = j;
			}
		}
		s[u] = true;						//加入集合
		int newdist = 0;					
		for (int j=1;j<VERTEX_COUNT;++j)	//调正dist[],这些值是只经过s中的点,现在s变化了,所以dist也协同变化
		{
			if (!s[j] && adj[u][j] != FLT_MAX)
			{
				newdist = dist[u] + adj[u][j];//很重要的一点,更新dist,只要根据新加入的点 u 来计算,因为以前的点已经计算过了
				if(newdist < dist[j])
				{
					dist[j] = newdist;
					prev[j] = u;
				}
			}
		}
	}


	//test
	float dist[VERTEX_COUNT]={0.0};
	int prev[VERTEX_COUNT] = {0};
	float adj[VERTEX_COUNT][VERTEX_COUNT] = {{0,10,FLT_MAX,30,100},{FLT_MAX,0,50,FLT_MAX,FLT_MAX},
	{FLT_MAX,FLT_MAX,0,FLT_MAX,10},{FLT_MAX,FLT_MAX,20,0,60},{FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX,0}};
	dijkstra(0,adj,dist,prev);
	for(int i=0;i<VERTEX_COUNT;++i)
	{
		cout<<i+1<<" "<<dist[i]<<"("<<prev[i]+1<<")"<<endl;
	}
	//
}

//  [9/17/2013 qingezha] 和为sum ,加数为 1 到 n,随机选出若干个数,使之和为sum,整数相加,中兴面试
void find_factor(int sums, int n)   
{  
	list<int>list1;  
	int ie = 1;
	// 递归出口  
	if(n <= 0 || sums <= 0)  
		return;  
	// 输出找到的结果  
	if(sums == n)  
	{   
		// 反转list  
		list1.reverse();  
		cout<<ie++;
		for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)  
			cout<<" "<< *iter << " + ";  
		cout << n << endl;  
		list1.reverse();      
	}  
	list1.push_front(n);       //典型的01背包问题  
	find_factor(sums-n, n-1);   //放n,n-1个数填满sum-n  
	list1.pop_front();  
	find_factor(sums, n-1);     //不放n,n-1个数填满sum   

} 
list<int>list1; 
int ie = 1;
//  [10/8/2013 qingezha]给定一个数和一个数组,输出这个数组中若干个元素和为给定的那个数的所有情况
void find_factor(int sums, int *arr,int *end)//加数替换为一个数组arr 整数
{
	// 递归出口  
	if(arr == end)					//这里很重要,因为整数不像字符串,有'\0'结束标志,
		return;						//整数没有,所以用arr+sizeof(arr)/sizeof(int)表示地址
	// 输出找到的结果  
	if(sums == *arr)  
	{   
		// 反转list  
		list1.reverse();  
		cout<<ie++;
		for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)  
			cout<<" "<< *iter << " + ";  
		cout<<*arr;
		cout << endl;  
		list1.reverse();      
	}  
	list1.push_front(*arr);       //典型的01背包问题  
	find_factor(sums-*arr, arr+1,end);   //放n,n-1个数填满sum-n  
	list1.pop_front();  
	find_factor(sums, arr+1,end);     //不放n,n-1个数填满sum  
}
///**
//现有整型数组y{1,2,4,3,5,8},写出一个函数,找出所有和为10的集合
//**/
//
//#include <vector>
//#include <iostream>
//#include <algorithm>
//
//void print(std::vector<int>& vec)
//{
//	if(!vec.empty())
//	{
//		std::for_each(vec.begin(),vec.end(),[](const int& val)
//		{
//			std::cout<<val<<" ";
//		}
//		);
//		std::cout<<std::endl;
//	}
//}
//
//void fun(int*begin,int* end,std::vector<int>& vec,int sum)
//{
//	if(begin==end && sum==0)
//	{
//		print(vec);
//	}
//	else if(begin==end)
//	{
//		return ;
//	}
//	else
//	{
//		if(sum>=*begin)
//		{
//			vec.push_back(*begin);
//			fun(begin+1,end,vec,sum-*begin);
//			vec.pop_back();
//		}
//		fun(begin+1,end,vec,sum);
//	}
//}
//
//int main(int argc,char* argv[])
//{
//	std::vector<int> vec;
//	int arr[]={1,2,4,3,5,8};
//	fun(arr,arr+sizeof(arr)/sizeof(int),vec,10);
//	system("PAUSE");
//	return 0;
//}
//  [9/24/2013 qingezha] 有1分 2分 5分 10分无限张,求有多少种组合可以组合成 N 分
//	回溯解空间中寻找答案
int coins[4] = {1,2,5,10};
int total = 0;
vector<int> solution;
int count = 0;
void dfs(int index,int target)
{
	if (target == total)
	{
		++count;
		cout<<count<<":";
		for(int i=0;i<solution.size();++i)
			cout<<solution[i]<<" ";
		cout<<endl;
	}
	if(total>target) return;				//总和溢出了,就退回
	for (int i=index;i<4;++i)				//i 从 index 开始
	{
		total += coins[i];
		solution.push_back(coins[i]);		//放进去一个
		dfs(i,target);						//继续放,然后检查总和是否为target,
		solution.pop_back();
		total -= coins[i];
	}
}
//  [9/17/2013 qingezha] 最长递减序列  
//	动态规划:待求数组 a[size] ,最长 & 递减,现在用一个数组保存长度,另一个保存最长字母的对应的下一个
//	比如:d[i]表示 a 中 [i,size) 递减序列的最大长度,p[i] 表示 以a[i] 开头的最长递减序列的下一个字符
//  d[i] = max{d[k]| i<k<=size-1,a[i]>a[k]} 其中 a[i]>a[k] 很重要 
//	如果从前到后比较,需要找到最小的,然后与之比较,找到最小的麻烦;但是从后向前,只要找到最大的,而最大就是下标对应的
void longest_decrease_str(int *a,int size)
{
	//这样用size必须是常量!!!!!
	//int d[size];		//存储 i-size 之间的最长递减字符串的 长度
	//int p[size]; //存储 d[i]=max{d[k]| i<k<=n,a[i]>a[k]}+1,中的k
	int *d=new int[size]; //分配内存空间    
	int *p=new int[size];  //分配内存空间
	d[size-1] = 1;
	p[size-1] = a[size-1];
	int temp = 0;
	for (int i=size-2;i>=0;--i)
	{
		d[i] = 1;
		p[i] = -1;
		for (int j=i-1;j<size;++j)
		{
			temp = d[j] + 1; 
			//p[i] = -1; 这里写就错了,每次循环都付一次值
			if(a[i]>a[j] && temp>d[i])
			{
				d[i] = temp;
				p[i] = a[j];		//这里可以换成下标,而不是对应的字符
			} 
		}   
	} 
	temp = 0;
	int max = 0;
	for (int i=0;i<size;++i)
	{
		if(d[i]>temp)
		{
			temp = d[i];
			max = i;
		}
	} 
	int n = 0;
	do
	{
		cout<<a[max]<<" ";
		if(n == size-1) break;			//这点很重要,记住break,while里面条件不好判断,可以用break
		n = max;
		while(p[max]!=a[n])
			++n;
		max = n; 
	}while(n<size);

	delete[] d;
	delete[] p;
	//test
	//int  data[10]={9,8,2,5,4,3,2,7,1,0}; 
	//
}
//  [9/17/2013 qingezha] 在字符串中找出连续最长的数字串,并把这个串的长度返回,
int continumax(char **outputstr, char *intputstr)
{
	char *temp = NULL;
	int count = 0;
	int length = 0;
	while(*intputstr)
	{
		if(*intputstr>='0'&&*intputstr<='9')
		{
			temp = intputstr;
			while(*intputstr>='0'&&*intputstr<='9')
			{
				++count;
				++intputstr;
			}
			if (count>length)
			{
				length = count;
				*outputstr = temp;
			}
		}
		count = 0;
		++intputstr;
	}
	return length;
	//
	//char * p = " "; 
	//cout<<continumax(&p,"abcd12345ed125ss123456789")<<endl;
	//
}

// 如把字符串 abcdef 左旋转 2 位得到字符串 cdefab
// [start,end] 闭区间
void RotateString(char *p,int start,int end)
{
	char temp = ' ';

	while(start<=end)
	{ 
		temp = p[start];
		p[start] = p[end];
		p[end] = temp;
		++start;
		--end;
	}
}

//  要求时间对长度为 n 的字符串操作的复杂度为 O(n),辅助内存为 O(1)
char* LeftRotateString(char* pStr, unsigned int n)
{
	char *temp = pStr;
	unsigned int length = 0;
	while(*temp)
	{
		++length;
		++temp;
	}
	if(n>length) 
		n = n % length;
	if(n == 0) return pStr;
	RotateString(pStr,0,n-1);
	cout<<pStr<<endl;
	RotateString(pStr,n,length-1);
	cout<<pStr<<endl;
	RotateString(pStr,0,length-1);
	cout<<pStr<<endl;
	return pStr;
	//!!!! 这里不能用 char * p ="abcdef",这样p就不能修改里面的字符
	//
	//char p[7] = "abcdef"; 
	//LeftRotateString(p,2);
	//cout<<p;
	//
}
//char * strcpy_my(char * dest,char * src)
//{
//
//}
char* strcpy_my(char * dest,char * src) // 实现src到dest的复制
{
	if(!src||!dest)
		return NULL;
	char* stedest = dest;				//保存目标字符串的首地址
	while ((*dest++ = *src++)!='\0');	//把src字符串的内容复制到dest下
	return stedest;
}
//  [9/19/2013 qingezha] 洗牌算法
void shuffle(char *p,int length)
{
	if (p == NULL || length<=0)
		return;
	int num = 0;
	for (int i=0;i<length;++i)
	{
		num = rand()%(length - i) + i;
		swap(p[i],p[num]);
	}
}
//  [9/19/2013 qingezha] 腾讯 数组 arr ,然后调整数组每个元素的值 是 其余元素的乘积 
//	如a[0] 是a[1]*a[2]*...a[n-1]的乘积,a[1]是a[0]*a[2]*a[3]*...a[n-1]的乘积
void mul_tiplyarr(int *a,int lengths,int *out)
{
	int left = 1;
	int right = 1;
	for (int i=0;i<lengths;++i)
	{
		out[i] = 1;
	}
	for (int i=0;i<lengths;++i)
	{
		out[i] *= left;  
		out[lengths - 1 - i] *= right;    
		left *= a[i];
		right *= a[lengths - 1 - i];
	}
}
//  [9/19/2013 qingezha] 随机等概率取数字 取出一个就将后面的往前移动,空出的位置补0
int getNum(int *arr,int lengths)
{
	int i = lengths -1;
	for (;i>=0;--i)
	{
		if(arr[i]==0)
			continue;
		else break;
	}
	i = rand() % (i+1);
	int temp = arr[i];
	int j= i;
	for (;j<lengths-1;++j)
	{
		arr[j] = arr[j+1];
	}
	arr[j]=0;
	return temp;
} 
//  [9/19/2013 qingezha] 单链表递增排序 插入排序 将单链表切开 L->p1->p2->p3...
//	现在 L->p1 然后 r->p2->p3 遍历 r 取第一个元素,然后插入 L 中,相当于插入排序
void sort_singleLinklist(LinkPtr p)
{
	LinkPtr temp1 = p;			//p1
	LinkPtr r = new Node; 
	LinkPtr temp2;
	if (p != NULL)
	{
		r->next = temp1->next->next;		//r 头指针
		r->data = 0;
		temp1->next->next = NULL;			// 链表的next一定要初始化NULL !!!!!!!!!!!!很重要
		while(r->next != NULL)
		{
			temp2 = r->next;			//取出第一个指针   注意保留前一个指针temp1->next->data
			r->next = temp2->next;
			while(temp1->next !=NULL && temp1->next->data < temp2->data)
				temp1 = temp1->next;
			temp2->next = temp1->next;
			temp1->next = temp2;
			temp1 = p;
			
		}
	}
	//
	//int p[9] = {25,20,1,18,7,9,2,91,11}; 
	//LinkPtr head = new Node;
	//head->next = NULL;
	//for(int j=0;j<9;++j)
	//{
	//	LinkPtr t = new Node;
	//	t->data = p[j];
	//	t->next = head ->next;
	//	head->next = t;
	//}
	//sort_singleLinklist(head);
	//LinkPtr pp = head->next;
	//while(pp != NULL)
	//{
	//	cout<<pp->data<<" ";
	//	pp = pp->next;
	//}
	//
}
int rand7()//随机产生 1-7
{
	return rand()%7 +1;
}
int rand10()//利用 rand7() 随机产生 1-10  1-7 那我 用其 -1 后乘以  7,得到0,7,14...42,然后用rand7 相加,弥补其中的空白,就得到 1 - 49 均匀分布,然后取1-40,之后取余即可
{
	int i = 0;
	do 
	{
		i = (rand7() -1) * 7 + rand7();
	} while (i>40);
	return i%10 + 1;
}
//  [9/22/2013 qingezha] str 中只有英文字母 包括大小写
char* compress_count(char *str,int length)
{
	int sum_length = 0;
	int re_length = 0;
	char ch = ' ';
	char *des = new char[length];
	while(*str!='\0')
	{
		*des = *str;
		ch = *str;
		while(ch == *(++str))
		{
			++re_length;  
		}
		++des;
		if(re_length > 0)
			*des = re_length;
		re_length = 0; 
	} 
	return des;
}
//  [9/22/2013 qingezha] 注意指针类型要转换,不能对void 类型进行++运算
//	但当源内存和目标内存存在重叠时,memcpy会出现错误,
//	而memmove能正确地实施拷贝,但这也增加了一点点开销。
void * my_memcpy(void *des, void *src, size_t count)
{
	if(des == NULL || src == NULL || count <= 0) 
		return NULL;
	char *dess = (char *)des;			//这里要类型转换
	char *srcs = (char *)src;
	char *ret = dess;
	int temp = count;
	while(count)
	{
		*dess++ = *srcs++;
		--count;
	}
	*(ret + temp) = '\0';
	return ret;
}
//  [9/24/2013 qingezha] 判断地址重叠
void * my_memmov(void *dest, void *src, size_t n)
{
	{
		char*     d  = (char*) dest;
		const char*  s = (const char*) src;

		if (s>d)				//目的地址在前面,从头复制
		{
			while (n--)
				*d++ = *s++;
		}
		else if (s<d)			//目的地址在后面,从尾部复制
		{
			d = d+n-1;
			s = s+n-1;

			while (n--)
				*d-- = *s--;
		}
		return dest;

	}
}
//  [9/24/2013 qingezha] 寻找大于N的最小的质数
bool isPrime(int num)
{
	if(num < 2) return false;		//最小的质数是 2
	int temp = 2;
	while(temp<num)
	{
		if(num % temp == 0)
			return false;
		++temp;
	}
	return true;
}
int largetoNum(int num)
{
	if(num <= 0) return -1;
	int temp = num + 1;
	while(!(isPrime(temp)))
		++temp;
	return temp;
}

//  [9/26/2013 qingezha] 判断是否含有子树
//bool is_subtree(treePtr t1,treePtr t2)
//{
//	if (t1 == NULL && t2 == NULL)
//		return true;
//	else if(t1 != NULL && t2 != NULL)
//	{
//		if(t1->ch == t2->ch)
//			return is_subtree(t1->lchild,t2->lchild) && is_subtree(t1->rchild,t2->rchild);
//		else 
//			return is_subtree(t1->lchild,t2) || is_subtree(t1->rchild,t2);
//	}
//	else 
//		return false;
//	
//}
//  [9/28/2013 qingezha] 数组分割 有2N个数,总和为SUM,现在分割这个数组
//	每个数组的元素的个数为N,且这两个数组的和最接近
//	arr为数组指针,length 为数组长度且为偶数,数组下标是从1开始
//	d(i,j,s)指 1-i 中选出 j 个数,使其和不大于 s 的最大值
//	动态规划算法:d(i,j,s) 分2 种情况,取arr[i] 与不取 arr[i] 求其最大值
//	d(i-1,j,s) 与 d(i,j-1,s-arr[i]) + arr[i] 这2 者比较
#define length 10
#define sum		87
int near_division_arr(int *arr)
{
	/*int sum = 0;
	for (int i=1;i<length+1;++i)
		sum += arr[i];*/           //数组下标不能为变量!!!!!!!!!!!!
	int dp[length+1][length/2+1][sum/2+1];		//从长为length的数组中选出length/2个,且使选出来的数字之和不大于sum/2的最大值
	memset(dp,0,sizeof(dp));					//初始化为 0
	for (int i=1;i<length+1;++i)
	{
		for (int j=1;j<=min(i,length/2);++j)
		{
			for (int s=sum/2;s>=arr[i];--s)
			{
				dp[i][j][s] = max(dp[i-1][j][s],dp[i-1][j-1][s-arr[i]]+arr[i]);
			}
		}
	}
	int i = length;
	int j = length/2;
	int s = sum/2 + 1; 
	while(i>=1)
	{
		if(dp[i][j][s] == dp[i-1][j-1][s-arr[i]] + arr[i])
		{
			cout<<arr[i]<<endl; 
			--j;
			s -= arr[i];
		}
		--i;
		 
	}
	return dp[length][length/2][sum/2];


	//  [9/30/2013 qingezha] 切记 这是动态规划的核心,最优子结构 dp[j-1][s-arr[i]]+arr[i] , dp[j][s],
	//	取 N 件物品,总和不超过 sum/2 
	//int solve2()
	//{
	//	int i , j , s;
	//	int dp[N+1][SUM/2+2];     //取N+1件物品,总合不超过SUM/2+2,的最大值是多少 
	//	memset(dp,0,sizeof(dp));    //初始状态都为0 

	//	for(i = 1 ; i <= 2*N ; ++i)
	//	{
	//		for(j = 1 ; j <= min(i,N) ; ++j)
	//		{
	//			for(s = SUM/2+1 ; s >= arr[i] ; --s)    //01背包从大到小,可以省空间,即最外层的空间
	//			{
	//				dp[j][s] = max(dp[j-1][s-arr[i]]+arr[i] , dp[j][s]); 
	//			}
	//		}
	//	}
	//	//要求最优解则 空间不能优化,
	//	return dp[N][SUM/2+1];
	//}
	//int arr[] = {0,1,5,7,8,9,6,3,11,20,17};
	//const int NN=5;  //元素个数
	//const int SUM = 87; 
	//int solve2()
	//{
	//	int dp[NN+1][SUM/2+1];
	//	memset(dp,0,sizeof(dp));
	//	for (int i=1;i<=NN;++i)
	//	{
	//		for (int j=1;j<=min(i,NN);++j)
	//		{
	//			for (int s=SUM/2;s>=arr[i];--s)
	//			{
	//				dp[j][s]=max(dp[j][s],dp[j-1][s-arr[i]]+arr[i]);
	//			}
	//		}
	//	}
	//	return dp[NN][SUM/2];
	//}
	//int solve3()
	//{
	//	int i , j , s;
	//	int isOK[N+1][SUM/2+2]; //isOK[i][v]表示是否可以找到i个数,使得它们之和等于v
	//	memset(isOK,0,sizeof(isOK));    //都不合法
	//	//注意初始化
	//	isOK[0][0] = 1; //可以,取0件物品,总合为0,是合法的

	//	for(i = 1 ; i <= 2*N ; ++i)
	//	{
	//		for( j = 1 ; j <= min(i,N) ; ++j)
	//		{
	//			for(s = SUM/2+1 ; s >= arr[i] ; --s) //从大到小,数组少了一维
	//			{
	//				if( isOK[j-1][s-arr[i]] )
	//					isOK[j][s] = 1;
	//			}
	//		}
	//	}
	//	for(s = SUM/2+1 ; s >= 0 ; --s)
	//	{
	//		if(isOK[N][s])
	//			return s;
	//	}

	//	//要求最优解则空间不能优化
	//	return 0;
	//}

}

long StringToInt(char *ch) //功能测试,边界测试,负面测试(不符合常规代入参数)
{						   // 前面带 ‘+’ ‘-’代表正负,还有字符中出现字母需要判断
	if(!ch) return -1;	   // 就是不是数字的字符
	long num = 0;
	bool isPositive = false;
	if(*ch == '+')			//
	{
		isPositive = true;
		++ch;
	}
	else if(*ch == '-')		//
	{
		isPositive = false;
		++ch;
	}
	while(*ch)
	{
		if('0'<=*ch && *ch<='9') // '0'<=*ch<='9' 这样写就是 或 的关系
		{
			num = num * 10 + (*ch - '0');
			++ch;
		}
		else 
			return -1;
		
	}
	return isPositive ? num : -num ; //前面是bool 若真整体的值就是num,即前者
}
//  [9/29/2013 qingezha] 正数的开方 主要采用二分法,一个为0.0001 ,另外一个为value
//	mid 为二者的平均值,如果平均值的平方大于value则mid取上一次mid和0.0001之间的平均值
float my_sqrt(float value)
{
	float low = 0.0000001;
	float high = value>1?value:value+1;
	float mid = 0.0;
	float min = 0.0;
	do 
	{
		mid =(high + low)/2;
		min = mid * mid;
		if(min>value)
			high = mid;
		else
			low = mid;
	} while (abs(value - min)>=0.000001);
	return mid;
}
//  [9/30/2013 qingezha] // lowbit表示的是某个数从右往左扫描第一次出现1的位置
int	lowbit(int x)//输出x 的低位中的第一个1 位置
{
	return x&~(x-1);  //x 与 负x 相与 找到
}
void find(int *arr,int len)
{
	int xor = 0;
	int flips = 0;
	for (int i=0;i<len;++i)
		xor ^= arr[i];
	// 三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组 //正确
	for(int i=0;i<len;++i)
		flips ^=lowbit(xor ^ arr[i]);
	// 表示的是:flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)  
	int b = 0;				// 假设三个只出现一次的其中一个数为b
	for(int i=0;i<len;++i)
		if(xor ^ arr[i] == flips)
			b = arr[i];
	cout<<b<<endl;
	//test/
	//int arr[] = {1,5,7,1,5,7,12,11,13}; //共 11 个 
	//find(arr,9);
	//
}

//  [9/30/2013 qingezha] Union-Find 并查集
//	初始化所有的结点用整数表示,比如(0--n-1),在处理输入pair之前,他们分属于不同的组,每个结点都是孤立的
//	可以用数组表示这种关系,数组的index表示结点,而对应的值表示组号
int const NODE_NUM = 1001;
int count_set = NODE_NUM;
int arr[NODE_NUM]={0};
void UF_init()			//初始化
{ 
	for (int i=0;i<NODE_NUM;++i)
		arr[i] = i; 
} 
int find(int p)				//查找这个结点属于 哪个组
{
	if(p>=0&&p<NODE_NUM)
		return arr[p];
	else 
		return -1;
}
bool connect(int p,int q)		//判断是否连接
{
	if(p>=0 && p<NODE_NUM && q>=0 && q<NODE_NUM)
		return arr[p]==arr[q];
	else
		return false;
}
int count()					//组的个数
{
	return count_set;
}
bool union_two(int p,int q)	//合并2个,使之为一个组
{
	if(p>=0 && p<NODE_NUM && q>=0 && q<NODE_NUM)
	{
		if(arr[p]==arr[q])
			return true;
		else
			for(int i=0;i<NODE_NUM;++i)
				if(arr[i]==arr[p])
					arr[i] = arr[q];

		--count_set;
		return true;
	}
	else
		return false;

}

//  [10/7/2013 qingezha].给定一个源串和目标串,能够对源串进行如下操作:
//	1).在给定位置上插入一个字符
//	2).替换任意字符
//	3).删除任意字符
//	写一个程序,返回最小操作次数,使得对源串进行这些操作后等于目标串。
//	例如:源串”hello”,目标串”lleo”,则通过3次修改可以使得源串变成目标串(删除’h',删除’e',在’o'之前插入字符’e')
//也可以通过找到最长公共字串,然后2个原来串的长度和减去公共字串的长度即可
//用f[i][j]表示要修改的最少次数 源头x[1...i] 目标y[1...j],如果x[i]==y[j] 则f[i][j]=f[i-1][j-1]
//如果不同,则可以用增,删,改,分别对应的f[i][j-1]+1,f[i-1][j]+1,f[i-1][j-1]+1,
int cal_distance(const char *sta,const char *stb)
{
	if(sta == NULL || stb == NULL)
		return 0;  
	int f[10+1][5+1]={0};		//这里可以用new一个一维数组,代替栈上的二维数组,因为栈上的编译时就确定长度,堆上的运行时才确定
								//这里纯用于测试
	for (int i=0;i<11;++i) 
		f[i][0]=i;				//悲剧啊,这里误写成0 了
	for (int i=0;i<6;++i) 
		f[0][i]=i;				//悲剧啊,这里误写成0 了
	int temp = 0;
	for (int j=1;j<6;++j)	
	{
		for (int i=1;i<11;++i)	//j<6写成了i<6,以后要小心啊
		{
			if(sta[i]==stb[j])
				f[i][j]=f[i-1][j-1];
			else
			{
				temp = min(f[i-1][j-1]+1,f[i-1][j]+1);//这里是增,删,改对应的次数
				f[i][j]=min(f[i][j-1]+1,temp);
			}
			cout<<i<<" "<<j<<" "<<f[i][j]<<endl;
		}
	}
	return f[10][5];
	 
}

//  [9/30/2013 qingezha] 链表倒置 循环与递归形式
//	一般形式,1—>2->3->4 现在1<-2<-3<-4  那么改变1的next的时候需要保存指向2的指针,然后同理处理2
//	需要保存的,用直译(见词知意)的表达出来比如:pre前面,next后面,cur当前,然后循环后赋新值
LinkPtrs reverse_link(LinkPtrs root) //头指针指向的是第一个元素
{
	if(root == NULL)
		return NULL;
	LinkPtrs nextp = root->next;		//第一个结点
	LinkPtrs pre = root;			//保留前端
	LinkPtrs temp = NULL;
	LinkPtrs reverseHead = NULL;
	pre -> next = NULL;
	while(nextp->next)
	{
		temp = nextp -> next;		//先要保存下一个指针
		nextp -> next = pre;
		pre = nextp;
		nextp = temp;
	}
	nextp -> next = pre;
	reverseHead = nextp;
	return reverseHead;
}
//链表倒置,切记 方法很巧!!!!!!!!!!!!!!!!!!
LinkPtrs reverse_link_recursive(LinkPtrs root)
{
	if(root == NULL)
		return NULL;
	LinkPtrs cur,temp,revers_head;
	if(root->next == NULL)
		return root;			//链表如果只有一个结点,那么直接返回第一个
	else
	{
		cur = root;
		temp = cur -> next;		//temp 为2->3->4的头指针
		//可以认为后面的都已经倒过来了,且认为revers_head 为倒过来的链表的头指针
		//这样理解就容易多了
		revers_head = reverse_link_recursive(temp);
		temp -> next = cur;
		cur -> next = NULL;
	}
	return revers_head;
}
//  [9/30/2013 qingezha]实现一个函数,对一个正整数n,
//	算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去。
//奇数的时候加1或减1,完全取决于二进制的后两位,如果后两位是10、00那么肯定是偶数,选择除以2,
//如果后两位是01、11,那么选择结果会不一样的,如果是*****01,那么选择减1,如果是*****11,那么选择加1,
//特殊情况是就是n是3的时候,选择减1操作。
int func(unsigned int n)
{
	if(n==1)
		return 1;
	if(n%2==0)
		return 1 + func(n/2);
	if(n==3)
		return 2;				//3到1 共2步,先-1 后除以2,
	if(n&2)
		return 1 + func(n+1);
	else 
		return 1 + func(n-1);
}
//  [10/2/2013 qingezha] 数组子序列的个数,4,14,2,3和14,1,2,3都为4,13,14,1,2,3的子序列。 对于给出序列a,有些子序列可能是相同的,这里只算做1个,要求输出a的不同子序列的数量。
//	用一个数组记录出现2次或2次以上的数字,离当前数字最近的相同的数字的下标
//	比如1 2 3 4 2,一开始都为0,然后下标一次变为1 2 3 4,到新2 的时候 因为有2,所以要找到这个2的下标,才可以运算那个式子
//	所以用last_index记录数字的下标,里面是对应的arr[i],即要找的值2
#define Mod 1000000007
long sub_sequence(int *arr,int len) //整数数组不能检查越界,要已知长度
{
	long sub_arr[120] = {0};						
	int last_index[120] = {0};						//初始值这里设的好
	for (int iter=1;iter<=len;++iter)
	{
		switch(last_index[arr[iter-1]])
			{
		case 0:
			{
				sub_arr[iter] = 2 * sub_arr[iter-1]+ 1;
				break;
			}
		default:
			{
				sub_arr[iter] = 2 * sub_arr[iter-1] - sub_arr[last_index[arr[iter-1]]-1];//上一个相同的数字的下标
			}
		}
		last_index[arr[iter-1]] = iter;				//这里写错了last_index[iter-1],每一次都更新,按次序递增
	}
	return sub_arr[len];							//这里写错了 sub_arr[len-1]
	//test///
	//int arr[20] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
	//cout<<sub_sequence(arr,sizeof(arr)/sizeof(int));
	//

}
//  [10/3/2013 qingezha]已知线段长度,求覆盖最多的点数,(一个有序数组代表各个点)
int calculate_num(int *arr,int length,int seg_len)
{
	if(arr == NULL||length<=0 || seg_len<=0)
		return 0;
	int rear = length - 1;
	int front = 0;
	int max_num = 0;
	while(rear>=0)				//从最后一个点出发,依次减去前面的点的值,判断差值,然后记录点的个数
	{
		front = rear;
		while(front>=0)
		{
			if((arr[rear]-arr[front])<=seg_len)
				--front;
			else								//这里要记住,跳出循环
				break;
		}
		//换成while((arr[rear]-arr[front])<=seg_len) 更简洁
		max_num = rear-front > max_num ? rear - front : max_num;		//这里三元操作运算符
		--rear;
	}
	return max_num;
	//
	//	int arr[5] = {1,2,5,6,9};
	//  cout<<calculate_num(arr,5,2);
	//
}
//  [10/3/2013 qingezha] 真没想到可以从中间向两边出发,分别比较2边是否相同,注意回文个数是偶数/奇数情况
int getpalindrome(char *arr,int len)//获取最大的回文 
{
	int i = 0;
	int j = 0;
	int max = 0;
	for (i=0;i<len;++i)
	{
		for(j=1;i+j<len&&i-j>=0;++j) //回文是奇数的情况
			if(arr[i-j] !=arr[i+j])
				break; 
		if(2*j-1>max)
			max = 2*j - 1;
		for (j=1;i-j>=0&&i+j+1<len;++j)			//回文长度为偶数,认为与相邻的后面相同
			if(arr[i-j]!=arr[i+j+1])
				break;
		if(i+j+1==len&&2*j + 2>max)
			max = 2*j + 2;
		if(i+j+1==len&&2*j - 2>max)				//这里j在元素不等时跳出与for中条件不满足时跳出
			max = 2*j - 2;
	}
	return max;
}
//另外一种方法是abcgoogleaba,可以进行这样的操作:#a#b#c#g#o#o#g#l#e#a#b#a#
//中间插入#或其他字符
int getpalindrome_ss(char *arr,int len)//获取回文的最大长度
{
	int len2 = 2*len + 1;
	int j = 0;
	int i = 0;
	int max = 0;
	char *str = new char[len2];
	for (int i=0;i<len;++i)
	{
		str[2*i] = '#';
		str[2*i+1] = arr[i];
	}
	str[len2-1] = '#';					//中间插入“#”
	for(i=0;i<len2;++i)
	{
		for(j=1;i+j<len2&&i-j>=0;++j)  
			if(arr[i-j] !=arr[i+j])
				break; 
		if(2*j-1>max)
			max = 2*j - 1;
	}
	delete[] str;
	return max;
}
void get_n()
{
	int num = 20;   //控制输出个数
	int i = 1;
	int temp = 0; 
	while(1)
	{
		if(temp%3==2&&temp%5==3&&temp%7==2)
		{
			cout<<i<<" "<<temp<<endl;
			++i;
			if(i>num)
				break;
		}
		++temp;
	}
}
//  [10/10/2013 qingezha]最长相同字符
int  large_same(char *arr)
{
	if(arr == NULL)
		return -1;
	int count = 0;
	int max1 = 1;
	while(*(arr+1)!=0 && *arr == *(arr+1))
	{ 
		++arr;
		++max1;
	}
	if(*(arr+1)==0) 
		return max1;				//这里出口很重要!!!!可以举例,比如aabb带进去试试,看看有没返回值
	int max2 = large_same(++arr);	//别忘 了 是++,就是下一个
	return max2>max1?max2:max1; 
}
//  [10/10/2013 qingezha]没有重复出现的数字
unsigned int GetNotRepeatNum(unsigned int lValue)
{
	int count[10]={0};
	int temp = lValue;
	int index = 0;
	int i = 0;
	bool isfind = true;			//初始值为false 错了
	while(1)
	{
		while(lValue>0)				//这里出口1
		{
			index = lValue % 10;
			count[index]++;
			//if(count[index]>1)		//这里出口2
			//	break;
			lValue = lValue/10;

		}
		for (i=0;i<10;++i)				
			if(count[i]>1)				//只要有一个就为false,就跳出
			{							//另外跳出也有i<10的可能
				isfind = false; 
				break;
			}
			//else
			//	isfind = true;		//这里没写,错了
		for (int i=0;i<10;++i)
			count[i] = 0;
		if(!isfind)					//通过break出口
			lValue=++temp;
		if(i==10)					//通过i<10出口
			return temp;

	}
}
//  [10/6/2013 qingezha]遍历一个文件,里面元素个数不知道,让你设计一个算法遍历一遍,等概率的随机取出一个元素
//	可以这样:设现在遍历到第 i 个元素,现在判断如果 rand()%i为0则将返回值更新为第i个元素;否则不变
char get_equal_char(char *arr)
{
	if(arr == NULL)
		return NULL;
	int i = 1;
	char re_char = arr[0];
	char *temp = arr;
	while(*arr)
	{
		if(rand()%i==0)				//这里牛逼
			re_char = arr[i-1];
		++i;
		++temp;
	}
	return re_char;
}

//  [10/7/2013 qingezha] 求出1…n之间的所有亲和数。
//	所谓亲和数,即存在数a和数b,a的所有真因子之和等于b,b的所有真因子之和等于a,则称a和b为一对亲和数。
//	例如220的真因子为:1、2、4、5、10、11、20、22、44、55、110,和为284;而284的真因子为:1、2、4、71、142,和正好为220。故220和284是一对亲和数。
//	现在设j 的真因子和为sum[j],那么j 可以被所有的因子整除的和为sum[j] ,其中可以整除就是关键
void print_Affsum(int n)
{
	if(n<=0) 
		return;
	int *sum = new int[n+1];
	for (int i=1;i<n+1;++i) 
		sum[i]=1;				//所有亲和数都有因子 1
	for (int i=2;i<n/2;++i)		//i 作为因子,所以最大也只能为 n/2
	{
		for (int j=2*i;j<n+1;j+=i)//j 为可以整除 i,所以递增为 i
		{
			sum[j] += i;
		}
	}
	int i = 1;
	while(i<n+1)
	{
		if(sum[i]<n+1&&i==sum[sum[i]])		//这里别忘记检测sum[i]的值,因为sum[sum[i]]可能越界
			cout<<i<<" "<<sum[i]<<endl;
		++i;
	}
	delete[] sum;
}
//  [10/7/2013 qingezha]给出一个整型数组num[],和一特定值x,判断数组中是否存在一个或若干个元素之和为x,若存在则返回true,否则false。
bool is_sum(int *arr,int len,int x)
{
	if(arr==NULL||len<1)
		return false;
	if(len==1)
		return arr[0] == x;			//如果有,要么等于x,要么<= x-arr[i]
	for (int i=0;i<len;++i)
	{
		if (arr[i]==x||is_sum(arr+i+1,len-i-1,x-arr[i]))
			return true;
	}
	return false;
}
//  [10/10/2013 qingezha] 给出一个整型数组num[],对其中的每个元素,输出在它左侧且比它小的最近元素,
//	要求时间复杂度为O(n)。例如int num[]={2,4,1,3},2无左侧最近元素;4左侧最近的是2;1没有;3左侧最近的是1.(百度面试题)
// 输出每个元素中,在它左侧且比它小的最近元素
void PrintEachMin(int num[], int len)
{
	if(!num || len<=0)
		return ;

	stack<int> sta;

	// 对每个元素,进栈前先循环判断栈顶是否比它大,若是则该元素就是栈顶的左侧最近小元素
	// 此时输出结果后,弹出栈顶元素。最后将该元素压入栈
	for (int i=len-1; i>=0; --i){
		while(!sta.empty() && num[i]<sta.top()){
			printf("The nearest number of %d is %d!\n", sta.top(), num[i]);
			sta.pop();
		}
		sta.push(num[i]);
	}

	// 此时栈中的所有元素均不存在左侧最近小元素
	while(!sta.empty()){
		printf("%d haven't nearest number!\n", sta.top());
		sta.pop();
	}
}
//  [10/14/2013 qingezha]百钱买百鸡 公鸡5元 母鸡3 3只小鸡1,100买100只
void mai_ji()
{
	int num =0;
	int sum =0;
	for (int i=0;i<120;++i)
	{
		for (int j=0;j<133;++j)
		{
			for (int k=0;k<133;++k)
			{
				num = i+j+k*3;
				sum = 5*i+3*j+k;
				if(num==sum&&num==100)
					cout<<i<<" "<<j<<" "<<3*k<<endl;
			}
		}
	}
}
#include "empress.h"
#include <iostream>
using namespace std;
int qq[20]={0};//用于保存皇后所在的行数,从第一列开始存皇后所在的行数
int find(int i,int j)//判断i行j列是否合法
{
	int k=1;
	while(k<j)
	{
		if (qq[k]==i||abs(qq[k]-i)==abs(k-j))
		{
			return 0; 
		}
		k++;
	}
	return 1;
}
void place(int k,int n)
{
	if (k>n)
	{
		for (int i=1;i<=n;i++)
		{
			cout<<qq[i]<<" ";
		}
		cout<<endl;
	}
	else
	{
		for (int j=1;j<=n;j++)
		{
			if (find(j,k))
			{
				qq[k]=j;place(k+1,n);
			}
		}
	}
}
//  [10/2/2013 qqingezha]
int finds(int i,int j)//第i 行,第j 列 是否合法
{
	int temp = 1;				//temp 列,qq[列] = 行
	while(temp<j)
	{
		if(abs(j-temp) == abs(i-qq[temp])||qq[temp]==i)//这个忽略了;可能在同一行
			return 0;
		++temp;
	}
	return 1;
}


void places(int k,int n)		//第k个皇后,k从1开始
{
	if (k > n)
	{
		FILE *fp = fopen("D:\\t.txt", "a");
		for (int i=1;i<=n;++i)
			fprintf(fp, "%d ", qq[i]);  
		fprintf(fp,"\n");
		fclose(fp);
	}
	else
	{ 
		for(int j=1;j<=n;++j)	//行
			if(finds(j,k))
			{
				qq[k] = j;
				places(k+1,n); 
			}
	}
}






  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值