#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); } } }