注册 登录
编程论坛 C++教室

常用算法(C++描述)

live41 发布于 2004-10-17 11:08, 5669 次点击

由于最近看到论坛上的朋友的问题有很多是重复,所以开个接龙帖子,大家把经常用的算法以接龙的方式跟帖下去,以便后来者查询,请大家踊跃跟贴,请勿灌水,有问题请另外开贴提问!

要求:写清楚题目,算法思想和注释。

我会把帖子以索引的形式整理在1楼,标有“算法思想”的代表只给出最简单算法主干。

1、索引 2、裴波那契数列 3、josephus问题(算法思想) 4、遍历国际象棋棋盘 5、八皇后问题(算法思想) 6、汉诺塔问题 7、矩阵算法 8、符号转换表 9、四则混合运算 10、灌水

11、灌水 12、Selection Algorithm 13、有穷范围内(n)的偶数都可分解成两个素数之和(歌德巴赫猜想有穷实例前提证明) 14、复数运算(利用重载实现) 15、Selection Algorithm实现

感谢以下朋友提供算法(括号中的数字代表提供的数量):

corrupt (2) kappa314 (2) 三少爷 (1)

[此贴子已经被作者于2004-11-22 11:29:27编辑过]

31 回复
#2
live412004-10-17 11:12
裴波那契数列

//裴波那契数列(1,1,2,3,5,8……) //规律:f(1)=1,f(2)=1,f(n)=f(n-1)+f(n-2)...(n>2)

//循环算法(求前n个fibonacci数) #include<iostream.h> #include<iomanip.h> void main() { int fab1=1,fab2=1,fabn,n,i; cout<<"input the quantity number:"; cin>>n; cout<<setiosflags(ios::right)<<setw(3)<<fab1; cout<<setiosflags(ios::right)<<setw(3)<<fab2; for(i=3;i<=n;i++) { fabn=fab1+fab2; fab1=fab2; fab2=fabn; cout<<setiosflags(ios::right)<<setw(3)<<fabn; } cout<<endl; }

/*递归算法(求第n个fibonacci数) #include<iostream.h> #include<iomanip.h> int fibonacci(int); void main() { int n; cout<<"input the serial number:"; cin>>n; cout<<"the fibonacci you want is:" <<fibonacci(n)<<endl; } int fibonacci(int n) { if(n==1||n==2) return 1; else return fibonacci(n-1)+fibonacci(n-2); }*/

#3
live412004-10-17 11:14
josephus问题(算法思想)

//N个小孩围成一圈报数,凡是报到指定数字的小孩离开圈子 //打印最后剩下的小孩的号码

#include<iostream.h>

void main() { const int N=10; //假定有10个小孩 int kid[N],*p; int interval; //报到此数的小孩离开 int count=0,leave=0; //报数计数器和离开的小孩数

for(int i=0;i<N;i++) kid[i]=i+1; //给每个小孩一个号码

cout<<"please input the Count off number: "; cin>>interval;

while(leave!=N-1) //当离开人数不等于总人数 { for(p=kid;p<kid+N;p++) //从号码是1的小孩开始数

if(*p!=0) //已离开的小孩不用报数 { count++;

if(count==interval) //报到此数时 { count=0; //由1开始重新报数 cout<<*p<<" "; *p=0; //离开的小孩号码置零 leave++; } } }

p=kid;

while(*p==0) //最后只剩下一个号码不是0的小孩 p++;

cout<<endl<<"the last one is: "<<*p<<endl; }

#4
live412004-10-17 11:16
遍历国际象棋棋盘

求从棋盘的左下角到右上角的无循环路径的总数 #include"stdio.h" #define N 8 //因为算出来的数据太大,所以要算很久,可以改变N的值进行测试。 #include"iostream.h" //此算法采用回溯法

enum bin{fal,tr}; int top=0; long int num=0; int row[]={-1,-2,-2,-1,1,2,2,1}; int col[]={-2,-1,1,2,2,1,-1,-2}; bin mark[N][N];

struct stack { int x,y; int dir;}board[N*N];

void push(stack it) { board[top].x=it.x; board[top].y=it.y; board[top].dir=it.dir; mark[board[top].x][board[top].y]=tr; top++; }

stack pop() { --top; mark[board[top].x][board[top].y]=fal; board[top].dir++; return board[top]; }

bin empty() { if(top==0) return tr; else return fal; }

void main() { stack temp={N-1,N-1,-1}; push(temp); while(!empty()) { int g,h; temp=pop(); int i=temp.x; int j=temp.y; int dir=temp.dir; while(dir<8) { g=i+row[dir]; h=j+col[dir]; if((g<0)||(h<0)||(g>=N)||(h>=N)||mark[g][h]) dir++; else { if(g==0&&h==0) {num++;dir++;} else { temp.x=i; temp.y=j; temp.dir=dir; push(temp); i=g; j=h; dir=0; }//else }//else }//while }//while cout<<"the total number is:"<<num; getchar(); }//main

[此贴子已经被作者于2004-10-17 11:17:05编辑过]

#5
live412004-10-17 11:18
八皇后问题(算法思想)

八皇后问题由高斯提出,但是当时他自己没有完全解决掉,共有92个解,完全不同的解共有12种(考虑棋盘翻转)

问题:在国际象棋棋盘上放置八个皇后(很强的:-),使她们互不攻击,问共有多少种方法?

算法:可以用穷举法,穷举法通过循环或者递归来实现;还可以用试探法,同样可以用递归来实现(包含回溯).我想解决问题的核心就是算法,知道算法了,具体用什么语言来实现就不是很难了.

#include<stdio.h>

#define N 8 int layout[N];//布局 int key=0; int judge(int row, int col)//判断能否在(row,col)放下 { int i; for(i=0;i<row;i++) { if(layout[i]==col) return 0;//同一列 if(i-layout[i]==row-col) return 0;//同一条主对角线 if(i+layout[i]==row+col) return 0;//同一条副对角线 } return 1; } void lay(int row)//在row行上放Queen { int i; if (row==N)//放完N个Queen输出布局 { printf("\n%02d ", ++key); for(i=0;i<N;i++) printf("%c%d ",layout[i]+'a',i+1); } else { for(i=0;i<N;i++)//在i列上放Queen { layout[row]=i; if(judge(row,i)) lay(row+1); } } }

void main() { lay(0); printf("\n"); }

#6
live412004-10-17 11:19
汉诺塔问题

汉诺塔是一个经典的算法题,以下是其递归算法:

#include<iostream.h>

void hanio(int n,char,char,char);

void main() { char A='A',B='B',C='C'; int n=3; hanio(n,A,B,C); }

void hanio(int n,char A,char B,char C) { if(n==1) { cout<<"将第"<<n<<"个盘面从"<<A<<"柱搬到"<<C<<"柱上"<<endl; } else { hanio(n-1,A,C,B); cout<<"将第"<<n<<"个盘面从"<<A<<"柱搬到"<<C<<"柱上"<<endl; hanio(n-1,B,A,C); } }

运行结果是: 将第1个盘面从A柱搬到C柱上 将第2个盘面从A柱搬到B柱上 将第1个盘面从C柱搬到B柱上 将第3个盘面从A柱搬到C柱上 将第1个盘面从B柱搬到A柱上 将第2个盘面从B柱搬到C柱上 将第1个盘面从A柱搬到C柱上

这个不是从递归算法出发用栈消解得出的算法,而是直接从当前情况来判断移动的步骤。非递归算法:

#include<iostream.h> #include<vector>

using namespace std;

class Needle { public: Needle() { a.push_back(100); } void push(int n) { a.push_back(n); } int top() { return a.back(); } int pop() { int n = a.back(); a.pop_back(); return n; } int movenum(int n) { int i = 1;while (a[i] > n) i++; return a.size() - i; } int size() { return a.size(); } int operator [] (int n) { return a[n]; } private: vector<int> a; };

void Hanoi(int n) { Needle needle[3], ns; int source = 0, target, target_m = 2, disk, m = n; for (int i = n; i > 0; i--) needle[0].push(i); while(n) { if(!m) { source = ns.pop(); target_m = ns.pop(); m = needle[source].movenum(ns.pop()); } if(m % 2) target = target_m; else target = 3 - source - target_m; if(needle[source].top() < needle[target].top()) { disk = needle[source].top();m--; cout<< disk << " move " << (char)(source + 0x41) << " to "<< (char)(target + 0x41) << endl; needle[target].push(needle[source].pop()); if(disk == n) { source = 1 - source; target_m = 2; m = --n; } } else { ns.push(needle[source][needle[source].size() - m]); ns.push(target_m); ns.push(source); m = needle[target].movenum(needle[source].top()); target_m = 3 - source - target; source = target; } } }

void main() { Hanoi(6);//6个盘子的搬运过程 }

#7
live412004-10-17 11:25
矩阵算法

输入一个数(这里以3为例)打印以下距阵(回字矩阵):

1 1 1 1 1 1 1 2 2 2 2 1 1 2 3 3 2 1 1 2 3 3 2 1 1 2 2 2 2 1 1 1 1 1 1 1

#include<iostream.h> #include<iomanip.h> void main() { int n,a,b,i,j; cout<<"\ninput the number of the laps: "; cin>>n; cout<<endl; for(i=1;i<=2*n;i++) { for(j=1;j<=2*n;j++) { a=i>n?(2*n+1-i):i; b=j>n?(2*n+1-j):j; cout<<setw(3)<<(a=(a<b)?a:b); } cout<<'\n'; } cout<<endl; }

以1 1 1 1为例,分成两部分: 1 1 1 1 1 1 2 2 1 2 1 1 2 2 1 2 2 1 2 2 1 1 2 1 1 1 1 1 1 1 1 1

对应的数组坐标为: (0,3) (0,0)(0,1)(0,2)(0,3) (1,2)(1,3) (1,0)(1,1)(1,2) (2,1)(2,2)(2,3) (2,0)(2,1) (3,0)(3,1)(3,2)(3,3) (3,0)

对应的判断为: if((i+j)>=m) if((i+j)<=m)

a[i][j]=(i>=j)?(m-i):(m-j); a[i][j]=(i<=j)?(i+1):(j+1);

这样就可以确定赋值给上半边还是下半边了!

接下来的问题就是打印输出了!

if(j==(m-1)) cout<<endl;

#8
live412004-10-17 11:26
符号转换表

keywords: 注:keywords VC++没有实现出来,(直到2003也是,考虑到代码兼容问题),如需要使用应该#include<iso646.h>,具体内容: /* iso646.h standard header */ #ifndef _ISO646 #define _ISO646 #define and && #define and_eq &= #define bitand & #define bitor | #define compl ~ #define not ! #define not_eq != #define or || #define or_eq |= #define xor ^ #define xor_eq ^= #endif /* _ISO646 */

Digraphs: <% { %> } <: [ :> ] %: # %:%: ## 注:以上二元符号在VC++6.0下也没实现出来,VC++.net 2003里面可以使用

Trigraphs: ??= # ??( [ ??) ] ??< { ??> } ??/ ??' ^ ??! | ??- ~ ??? ? 注:以上三元符号VC++6.0就有了(狂晕~~~)

#9
corrupt2004-10-17 14:54

哈。那我 也写一个把, 计算器的,(但是太急了,只是后缀输入,不要 介意啊,以后扑上)

#include<iostream.h> #include<math.h> class NODE { friend class STACK; NODE * NEXT; float DATA; }; class STACK { private: NODE *HEAD; public: STACK() { HEAD=0; } void push(float Data) { NODE *P=new NODE; P->DATA=Data; if(HEAD==0) { P->NEXT=0; HEAD=P; } else { P->NEXT=HEAD; HEAD=P; } } float pop() { float Data; NODE *q,*n; Data=HEAD->DATA; n=q=HEAD; HEAD=q->NEXT; delete q; return Data; } }; class Calulator { private: STACK s; public: void compute(char op); void run(); }; void Calulator::compute(char op) { float opend1=s.pop(); float opend2=s.pop(); switch(op) { case '+': s.push(opend1+opend2); break; case '-': s.push(opend1-opend2); break; case '*': s.push(opend1*opend2); break; case '/': s.push(opend1/opend2); break; case '^': s.push(pow(opend1,opend2)); break; } } void Calulator::run() { char c; float newoperate; cout<<"press enter calulator:"; while(cin>>c,c!='=') { switch(c) { case '+': case '-': case '*': case '/': case '^': compute(c); break; default: cin.putback(c); cin>>newoperate; s.push(newoperate); break; } } cout<<"the result is:"<<s.pop()<<endl; } int main() { Calulator calc; calc.run(); return 0; }

输入: 4 3 * 2 + = 回车

输出 14

///////////需要注释

[此贴子已经被zinking于2005-10-21 13:47:35编辑过]

#10
北雪の月弦2004-11-04 07:27
想问一下,大数的加, 减, 乘, 除该怎么算呀?
#11
风中涟漪2004-11-05 16:58
以下是引用北雪の月弦在2004-11-04 07:27:24的发言: 想问一下,大数的加, 减, 乘, 除该怎么算呀?
用数组处理进位
#12
kappa3142004-11-06 09:32

我出一个,很简单的,Selection Algorithm,

该算法的功能是:1。Sorting the list in decreasing order, and then the Kth largest value will be in position K.

2。A related technique to this would be to find the largest value and then move it to the last location

in the list. If we again look for the largest value in the list, ignoring the value we already found,

we get the second largest value, which can be moved to the second last location in the list.

If we con tinue this process, we will find the Kth largest value on the Kth pass.

This gives the algorithm:

#include"iostream"

using namespace std;

void Find_Kth_Largest(int list[],int n,int k){

//list:the value to look through

//n:the size of the list

//k:the element to select

int i,largest,largest_location,j;

for(i=1;i<=k;i++){//for_1

largest=list[1];

largest_location=1;

for(j=2;j<=n-(i-1);j++){//for_2

if(list[j]>largest){

largest=list[j];

largest_location=j;

}//if

}//for_2

swap(list[n-(i-1)],list[largest_location]);//exchanging, making the largest elements

//in the last elements of the list

}//for_1

cout<<"The number is:"<<largest<<"\n";

}//Find_Kth_Largest

void swap(int &a,int &b){//exchange

int temp;

temp=a;

a=b;

b=temp;

}//swap

void main(){

int List[16],K,i;

cout<<"Please input the K:";

cin>>K;

cout<<"\n";

List[0]=0;

for(i=1;i<=15;i++){

List[i]=2*i-1;

List[0]++;//List[0] is stored the length of the List

}//for

cout<<"\n"<<List[0]<<"\n";//output the length

Find_Kth_Largest(List,List[0],K);

}

需要翻译

[此贴子已经被zinking于2005-10-21 13:44:26编辑过]

#13
三少爷2004-11-12 23:18

偶来个,,看上去挺吓人的,其实更简单~

/*【Background】

Personally it's considered as meaningful in exercise

【Problem Description】

求n之内的所有偶数表示为两个素数之和。 注:歌德巴赫猜想是要证明对任何大于6的自然数n命题成立。

【Input Example】

10

【Output】

6=3+3

8=3+5

10=3+7 */

file://IDE:VC++6.0 file://long型最大值范围内求解素数(之所以只是用long,因为范围再大也是一样永远是有限个数无法完全 file://证明此命题,只是一个示例验证罢了) file://素数就用的那经典判定法:2到此数square root不能被此数整除 #include <iostream.h> #include <math.h> #include <conio.h>

bool isPrime(long n) { for(int i=2;i<=sqrt(n);i++) if(n%i==0) return false; return true; }

int main() { long n; cin>>n; for(long i=6;i<=n;i+=2) for(long j=3;j<=i;j+=2) if(isPrime(j)&&isPrime(i-j)) { cout<<i<<"="<<j<<"+"<<i-j<<endl; break; } getch(); return 0; }

#14
corrupt2004-11-13 19:22

我水,就写个简单点的好了(复数——学习重载最好了)

#include<iostream.h> class Fushu { public: Fushu(){}; Fushu(float r,float i); friend Fushu operator +(Fushu &c1,Fushu &c2); friend Fushu operator -(Fushu &c1,Fushu &c2); friend Fushu operator *(Fushu &c1,Fushu &c2); friend Fushu operator /(Fushu &c1,Fushu &c2); void display(); private: float real; float imag; }; Fushu::Fushu(float r,float i) { real=r; imag=i; } void Fushu::display() { if(real!=0) { if(imag>0) { if(imag=1) cout<<real<<"+i"<<endl; else cout<<real<<"+"<<imag<<"i"<<endl; } if(imag<0) cout<<real<<imag<<"i"<<endl; else cout<<real<<endl; } else { if(imag>0) { if(imag=1) cout<<"i"<<endl; else cout<<"+"<<imag<<"i"<<endl; } if(imag<0) cout<<imag<<"i"<<endl; if(imag=0) cout<<"0"<<endl; } } Fushu operator +(Fushu &c1,Fushu &c2) { Fushu temp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; return temp; } Fushu operator -(Fushu &c1,Fushu &c2) { Fushu temp; temp.real=c1.real-c2.real; temp.imag=c1.imag-c2.imag; return temp; } Fushu operator *(Fushu &c1,Fushu &c2) { Fushu temp; temp.real=c1.real*c2.real-c1.imag*c2.imag; temp.imag=c1.real*c2.imag+c2.real*c1.imag; return temp; } Fushu operator /(Fushu &c1,Fushu &c2) { Fushu temp; float tt; tt=c2.real*c2.real+c2.imag*c2.imag; temp.real=(c1.real*c2.real+c1.imag*c2.imag)/tt; temp.imag=(-c1.real*c2.imag+c2.real*c1.imag)/tt; return temp; } int main() { Fushu x(1,1),y(1,-1),z; z=x+y; z.display(); z=x-y; z.display(); z=x*y; z.display(); z=x/y; z.display(); return 0; }

#15
kappa3142004-11-22 03:58

我把书上的Selection Algorithm编程实现了:

#include"iostream"

using namespace std;

void Find_Kth_Largest(int list[],int n,int k){

//list:the value to look through

//n:the size of the list

//k:the element to select

int i,largest,largest_location,j;

for(i=1;i<=k;i++){//for_1

largest=list[1];

largest_location=1;

for(j=2;j<=n-(i-1);j++){//for_2

if(list[j]>largest){

largest=list[j];

largest_location=j;

}//if

}//for_2

swap(list[n-(i-1)],list[largest_location]);//exchanging, making the largest elements

//in the last elements of the list

}//for_1

cout<<"The number is:"<<largest<<"\n";

}//Find_Kth_Largest

void swap(int &a,int &b){//exchange

int temp;

temp=a;

a=b;

b=temp;

}//swap

void main(){

int List[16],K,i;

cout<<"Please input the K:";

cin>>K;

cout<<"\n";

List[0]=0;

for(i=1;i<=15;i++){

List[i]=2*i-1;

List[0]++;//List[0] is stored the length of the List

}//for

cout<<"\n"<<List[0]<<"\n";//output the length

Find_Kth_Largest(List,List[0],K);

}

#16
唐伯猫2005-08-09 18:14
都是高手啊!
#17
Wolfelee2005-08-09 23:10
引用:===》 “josephus问题(算法思想)

//N个小孩围成一圈报数,凡是报到指定数字的小孩离开圈子 //打印最后剩下的小孩的号码

#include<iostream.h>

void main() { const int N=10; //假定有10个小孩 int kid[N],*p; int interval; //报到此数的小孩离开 int count=0,leave=0; //报数计数器和离开的小孩数

for(int i=0;i<N;i++) kid[i]=i+1; //给每个小孩一个号码

cout<<"please input the Count off number: "; cin>>interval;

while(leave!=N-1) //当离开人数不等于总人数 { for(p=kid;p<kid+N;p++) //从号码是1的小孩开始数

if(*p!=0) //已离开的小孩不用报数 { count++;

if(count==interval) //报到此数时 { count=0; //由1开始重新报数 cout<<*p<<" "; *p=0; //离开的小孩号码置零 leave++; } } } ” 其中: “while(leave!=N-1) //当离开人数不等于总人数” 中注释是不是应该“//当离开人数不等于总人数‘减1啊?’”

#18
wwwindowsxp2005-10-18 16:12
关于汉诺塔问题的另类解
汉诺塔的终极经典的算法。 可以随手画出答案的方法。 http://bbs.ddvip.net/forumdisplay.php?f=32
汉诺塔.pdf

[此贴子已经被作者于2005-10-18 16:20:44编辑过]

#19
zinking2005-10-18 18:41
这样的代码未尝不好,只是读起来实在费解阿,我提议帖子的作者把
你们自己的代码加上详细的注解,
这样才真正帮助了大家提高了思想。
不只过不过份
特别是kai阿,knocker阿,在这里可以秀一下了。
#20
whaozhe2005-10-21 11:56
我想学编程!!!



真的!1
#21
sailer2005-10-22 01:32
希望多多编写这样的文章啊!
#22
vblue1302005-10-22 11:06
我完全同意zinking的说法
#23
vblue1302005-10-22 19:02
不错
#24
想你的天空2005-10-25 22:18

关于一元多项式的, 保证能运行 #include"multinomial.cpp" int main() { polyNomial<double> pa,pb,add,sub,mul; pa.creatPoly(); cout<<pa<<endl; pb.creatPoly(); cout<<pb<<endl<<endl;

add.addPoly(pa,pb,add); cout<<add<<endl; add.countValue(); sub.subPoly(pa,pb,sub); cout<<sub<<endl; sub.countValue();

mul.mulPoly(pa,pb,mul); cout<<mul<<endl; mul.countValue(); system("pause"); return 0 ; } #include<iostream> using namespace std;

template<class T> class polyNomial; template<class T> class polyNode { friend class polyNomial<T>; public: polyNode(){} private: T quotiety; //项的系数 T quotiety_degree;//项的指数 polyNode<T> *next; };

template<class T> ostream& operator<<(ostream& outs,const polyNomial<T>& x);

template<class T> class polyNomial { public: polyNomial(){ first = new polyNode<T>; } //置空表 ~polyNomial(); polyNomial<T> *creatPoly(); //操作结果:输入m项的系数和指数,建立一元多项式p ,并调用sort() bool isEmpty(); //多项式存在返回false,否则返回true polyNomial<T> *order(); //前条件:已经存在多项式 //后条件:把多项式按指数高到低排序 polyNomial<T> *addPoly(polyNomial<T>& pa,polyNomial<T>& pb, polyNomial<T>& pc); //前条件:存在多项式pa,pb //后条件:完成多项式加法运算,pc = pa+pb, 并调用sort() polyNomial<T> *subPoly(polyNomial<T>& pa,polyNomial<T>& pb,polyNomial<T>& pc); //前条件:存在多项式pa,pb //后条件:完成多项式加法运算,pc = pa-pb, 并调用sort() polyNomial<T> *mulPoly(polyNomial<T>& pa,polyNomial<T>& pb, polyNomial<T>& pc); //前条件:存在多项式pa,pb //后条件:完成多项式加法运算,pc = pa*pb , 并调用sort() polyNomial<T> *sort(); //前条件:存在要整理的多项式 //按指数高到低排序,整理多项式,把系数是0的项删除 void countValue(); //前条件:存在要计算的多项式 //计算多项式的值 void output(ostream& outs) const ; //前条件:存在多项式 //后条件:输出多项式 ostream& operator<< <>(ostream& outs,const polyNomial<T>& x); //重载输出流 private: mutable T polyNumber; //项数 polyNode<T> *first; }; #include "multinomial.h" #include "math.h" //创建多项式函数 template<class T> polyNomial<T> *polyNomial<T>::creatPoly() { polyNode<T> *link,*s; link = first; cout<<"输入提示:先输入有多少项,然后输入谋项的系数后按回车,接着输入对应的指数再回车" <<"(2^3是代表2的3次方的意思),未知数用y表示"<<endl; cout<<"输入多项式的项数"<<endl; cin>> polyNumber ; for(int i = 0; i < polyNumber ; i++) { cout<<"输入多项式的系数"<<endl; label1: s = new polyNode<T>; cin>>s->quotiety; if(s->quotiety == 0) { cout<<"系数不能为0!请重新输入该项"<<endl; goto label1; } cout<<"输入多项式的指数"<<endl; cin>>s->quotiety_degree; link->next = s; link = s; } link->next = NULL; sort(); return this; }

//析构函数 template<class T> polyNomial<T>::~polyNomial<T>() { polyNode<T>* link; while(first) { link = first->next; delete first; first = link; } }

//判断多项式是否为空 template<class T> bool polyNomial<T>::isEmpty() { if(first->next == NULL) return true; else return false; }

//排序 template<class T> polyNomial<T> *polyNomial<T>::order() { polyNode<T> *p = first->next; polyNode<T> *q = first->next; T _quotiety; T _quotiety_degree;

for( ; p ; p = p->next ) for( q = p->next ; q ; q = q->next ) if( (p->quotiety_degree)< (q->quotiety_degree)) { _quotiety = p->quotiety ; _quotiety_degree = p->quotiety_degree; p->quotiety = q->quotiety; p->quotiety_degree = q->quotiety_degree; q->quotiety = _quotiety; q->quotiety_degree = _quotiety_degree; } return this; }

//多项式相加函数 template<class T> polyNomial<T> *polyNomial<T>::addPoly(polyNomial<T>& pa,polyNomial<T>& pb,polyNomial<T>& pc) { //多项式的项已经以指数高到低的顺序排序了 polyNode<T> *p1 = pa.first->next; polyNode<T> *p2 = pb.first->next; polyNode<T> *link,*s; link = pc.first; // link 指向pc多项式(初始pc是空的)

while( p1 && p2 ) { if((p1->quotiety_degree)==(p2->quotiety_degree)) { //如果指数相同,则pa,pb的系数相加 s = new polyNode<T>; s->quotiety = p1->quotiety + p2->quotiety; s->quotiety_degree = p1->quotiety_degree;

link->next = s; link = s; p1 = p1->next ; p2 = p2->next ; }

else { //pa,pb的指数不同 s = new polyNode<T>; //把pa插入pc的最后1个节点 s->quotiety = p1->quotiety; s->quotiety_degree = p1->quotiety_degree; link->next = s; link =s; p1 = p1->next ; s = new polyNode<T>; //把pb插入pc的最后1个节点 s->quotiety = p2->quotiety; s->quotiety_degree = p2->quotiety_degree; link->next = s; link =s; p2 = p2->next ; } }

while (p1) //若pb的项数为空,则把pa继续插入pc的最后 { s = new polyNode<T>; s->quotiety = p1->quotiety; s->quotiety_degree = p1->quotiety_degree; link->next = s; link =s; p1 = p1->next ; }

while (p2 ) //若pa的项数为空,则把pb继续插入pc的最后 { s = new polyNode<T>; s->quotiety = p2->quotiety; s->quotiety_degree = p2->quotiety_degree; link->next = s; link =s; p2 = p2->next ; } link->next = NULL; sort(); return this; }

//多项式相减函数 template<class T> polyNomial<T> *polyNomial<T>::subPoly(polyNomial<T>& pa,polyNomial<T>& pb,polyNomial<T>& pc) { //多项式的项已经以指数低到高的顺序排序了 polyNode<T> *p1 = pa.first->next; polyNode<T> *p2 = pb.first->next; polyNode<T> *link,*s; link = pc.first; // link 指向pc多项式(初始pc是空的)

while( p1 && p2 ) { if((p1->quotiety_degree)==(p2->quotiety_degree)) { //如果指数相同,则pa,pb的系数相减 s = new polyNode<T>; s->quotiety = p1->quotiety - p2->quotiety; s->quotiety_degree = p1->quotiety_degree; link->next = s; link = s; p1 = p1->next ; p2 = p2->next ; }

else { //pa,pb的指数不同 s = new polyNode<T>; //把pa插入pc的最后1个节点 s->quotiety = p1->quotiety; s->quotiety_degree = p1->quotiety_degree; link->next = s; link =s; p1 = p1->next ;

s = new polyNode<T>; //把pb插入pc的最后1个节点 s->quotiety = p2->quotiety * -1; s->quotiety_degree = p2->quotiety_degree; link->next = s; link =s; p2 = p2->next ; } }

while (p1) //若pb的项数为空,则把pa继续插入pc的最后 { s = new polyNode<T>; s->quotiety = p1->quotiety; s->quotiety_degree = p1->quotiety_degree; link->next = s; link =s; p1 = p1->next ; }

while (p2 ) //若pa的项数为空,则把pb继续插入pc的最后 { s = new polyNode<T>; s->quotiety = p2->quotiety * -1; s->quotiety_degree = p2->quotiety_degree; link->next = s; link =s;

p2 = p2->next ; } link->next = NULL; sort(); return this; } //多项式相乘函数 template<class T> polyNomial<T> *polyNomial<T>::mulPoly(polyNomial<T>& pa,polyNomial<T>& pb, polyNomial<T>& pc) { polyNode<T> *p1 = pa.first->next; polyNode<T> *p2 = pb.first->next; polyNode<T> *link,*s; link = pc.first; // link 指向pc多项式(初始pc是空的) while(p1) { while(p2) //pa里的第1项和pb里的每一项,类推 { s = new polyNode<T>; s->quotiety = p1->quotiety * p2->quotiety; s->quotiety_degree =p1->quotiety_degree + p2->quotiety_degree; link->next = s; link = s; if(p2) p2 = p2->next;

} if(p1) p1 = p1->next; p2 = pb.first->next;

} link->next = NULL; sort(); return this ; } //整理新链表 template<class T> polyNomial<T> *polyNomial<T>::sort() { polyNode<T> *link; polyNode<T> *q; order(); //按指数从高到低排序 //整理链表:把相邻的元素比较,若指数相同的,则相加的结果放到比较的第2个项,并删除与之相连的项

link = first ; //link指向当前指针的前驱

q = link->next ; for( ; q!=NULL ; link = link->next , q = link->next) { if(q->next!=NULL) { if(q->quotiety_degree == q->next->quotiety_degree) {//若指数相同的,则把相加的结果放到比较的第2个项 q->next->quotiety += q->quotiety; //指数相同的系数相加,指数不变 if(q->next!=NULL) link->next = q->next; //删除与之相连的项 q = q->next ; } //删除系数为0的项 } if(q->quotiety == 0) { if(q->next == NULL) //判断删除的是不是最后1项 { link->next = NULL; break; } else { link->next = q->next; q = q->next ; } } } return this; } //计算机多项式的值 template<class T> void polyNomial<T>::countValue() { polyNode<T> *link = first->next; double sum = 0 ; double tem = 0,y ; cout<<"输入y的值用来求当前多项式的值:"<<endl; cin>>y; sort(); for( ; link ; link = link->next ) { if(link->quotiety_degree == 1) sum += link->quotiety * y ; else if(link->quotiety_degree == 0) sum += link->quotiety ; else { tem = pow(y,link->quotiety_degree) ; sum += link->quotiety * tem; tem = 0 ; } } cout<<"y="<<y<<"的当前多项式的值是: "<<sum<<endl; } //输出 template<class T> void polyNomial<T>::output(ostream& outs) const { polyNode<T> *current; polyNode<T> *p; outs<<"结果是:(建立2个多项式完后,将按顺序输出2个多项式+ - *后的多项式)"<<endl; current = first ; for( p = current->next ; p != NULL; current = current->next , p = current->next) //current指向当前节点的前驱, p指向当前节点 { if(p->quotiety == 0) //如果项系数是0的项,则删除 { if(p->next == NULL) current->next = NULL; else { current->next = p->next ; p = p->next ; } } if(p->quotiety > 0) //指数为0的项 { //系数为>0则打印+,指数为=1则打印y //指数为0的情况,则不打印 y if(p->quotiety_degree == 0) { if(p->quotiety>0) outs<<"+"<< p->quotiety; else if(p->quotiety < 0) outs<<p->quotiety; } else { if(p->quotiety!=1) //系数>0且系数 !=1 的情况 { if(p->quotiety_degree != 1) outs<<"+" << p->quotiety<<"y" <<"^"<<p->quotiety_degree; else outs<<"+" << p->quotiety<<"y"; } else //系数>0且系数 = 1 的情况 { if(p->quotiety_degree != 1) //系数等于1, 指数不等于1 outs<<"+"<<"y"<<"^"<<p->quotiety_degree; else //指数等于1的情况 outs<<"+"<<"y"; } } } else //系数<0的情况 { //系数为<0则打印+,指数为=1则打印y if(p->quotiety != -1) { if(p->quotiety_degree != 1) outs<< p->quotiety<<"y" <<"^"<<p->quotiety_degree; else outs<<p->quotiety<<"y"; } else //系数<0且系数 = -1 的情况 { if(p->quotiety_degree != 1) //系数等于1, 指数不等于1 outs<<"-"<<"y"<<"^"<<p->quotiety_degree; else //指数等于1的情况 outs<<"-"<<"y"; } }

} } //重载<< template<class T> ostream& operator<<(ostream& outs,const polyNomial<T>& x) { x.output(outs); return outs; }

#25
zinking2005-10-25 22:27
这么大段的代码看起来累死了
我要是来注释它的话,我得减寿10年
怪不得盖茨他爹说超过50行的代码不看那
#26
wwwindowsxp2005-10-26 09:30
以下是引用wwwindowsxp在2005-10-18 16:12:43的发言: 汉诺塔的终极经典的算法。 可以随手画出答案的方法。 http://bbs.ddvip.net/forumdisplay.php?f=32
汉诺塔.pdf

/*汉诺塔的递归算法* #include<iostream.h>

void hanio(int n,char A,char B,char C)

{

if(n==1)

{

cout<<"将第"<<n<<"片金片从"<<A

<<"柱搬到"<<C<<"柱上"<<endl;

}

else

{

hanio(n-1,A,C,B);

cout<<"将第"<<n<<"片金片从"<<A

<<"柱搬到"<<C<<"柱上"<<endl;

hanio(n-1,B,A,C);

}

}

void main()

{

char A=''A'',B=''B'',C=''C'';

int n=3;

hanio(n,A,B,C);

}

*/

/****关于汉诺塔问题的另类解***** 汉诺塔问题归于中序遍历,采用递归算法或分治算法也许的最简单的求解方法。

递归是设计和描述算法的一种有力的工具。能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。

分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。

如果原问题可分割成k个子问题(1<k≤n),且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。

当然,有时我们并不需要求解出问题的全解。如我们只想知道64片金片要从A柱上移动到C柱上(B柱为桥),第一百亿步应该是哪片金片的第几次移动,且是从哪根柱上移动到哪根柱上呢?在计算机上是否能用递归算法或分治算法求解我不知道,但在只有一支笔一张纸的情况呢?我想用递归法或分治法是不现实的!那有没有方法求解呢,答案是肯定的。我通过递推法(利用问题本身所具有的一种递推关系求问题解的一种方法)找到了解决这个问题的数学表达式:

(2^i)*(2^j-1)=M;k=j%3; N; 条件:N金片数,第M步为已知。(金片1为最小,金片64最大)那么解就是:N片金片的第M步为金片i+1的第j次移动,当(i+1)%2=N%2时,k=0:从B柱上移动到A柱上;k=1:从A柱上移动到C柱上;k=2:从C柱上移动到B柱上;当(i+1)%2≠N%2时,k=0:从C柱上移动到A柱上;k=1:从A柱上移动到B柱上;k=2:从B柱上移动到C柱上;

如果此时想知道各柱上的金片是如何排列的却只有使用另一种方法了。那就是先用N位二进制数来表示M,余下的工作就是随手画出各柱上的金片的排列!再画出第M-1步各柱上的金片的排列,那么就可以不用计算而得到答案!这正是我为大家推荐的方法。

请仔细阅读程序中蓝色字体部分,我想信你也能随手画出答案!(提示:用N位二进制数来表示M,最高位代表最大的金片,最低位为最小。先从最高位开始,为1则最大的金片用N表示画在C柱上,否则在A柱上;次高位如果同上一位相同则画在同一柱上,否则画在B柱上;下一次高位如果同次高位同则画在同一柱上,否则画在A柱上;依此循环。并遵守在同一柱上相邻的两片金片编号不能同时为奇或偶。从低位往高位看,第一位为1的金片就是本次移动的金片,且在大多数情况下不用画出第M-1步各柱上的的排列就能知道该金片的如何移动的。例:4张金片第10步,10=(1010)2 显然A柱上有2,B柱上是3,C柱上有1和4。第一位为1在第2位上,因此是金片2,

1+(1010)2>>2 =1+(0010)2 =3,显然 4张金片第10步为金片2的第3次移动,且是从B柱移动到A柱。)

*********************************************/

/*********************************************

* 文件名称:hanio.cpp

* 摘 要:汉诺塔的终极经典的算法。

* 可以随手画出答案的方法。

* 本例没考虑程序本身的可读性和效率。

* 当前版本:1.0

* 作 者:赵智强

* 完成日期:2005年10月12日

* 电子邮箱:wwwindowsxp@163.com

* 腾讯 QQ : 191580647

* 测试环境:Turbo C++ 3.0

*********************************************/

#include<iostream.h>

void divtwo(int d[],int n)

{

int temp=0,cy=0;

int i;

for(i=n;i>=0;i--)

{

cy=d[i]%2;

d[i]=(d[i]+temp*10)/2;

temp=cy;

}

}//十进制数组除2

void multwo(int d[],int m,int n)

{

int temp=0,cy=0;

int i,j;

for(j=0;j<n;j++)

{

for(i=0;i<m;i++)

{

cy=(d[i]*2)/10;

d[i]=(d[i]*2)%10+temp;

temp=cy;

}

}

}//十进制数组=2^m

void decaddone(int d[],int n)

{

int i;

for(i=0;i<n;i++)

{

if(d[i]==9) d[i]=0;

else {d[i]+=1;break;}

}

}//十进制数组加1

void main()

{

int i,j,k, n;

int m=52;

char a[52]="1";

int b[52]={0};

int d[52]={1};

int e[52]={0};

cout<<"Input :disk(1~100) " //输入金片数:整型

<<"step(2^disk-1)"<<endl;//输入第M步:字符数组

cin>>n;

if(n>100){cout<<"disk err! (disk>100)"

<<endl; return;}

int c[100]={0};

int aa[100]={0};

int bb[100]={0};

int cc[100]={0};

for(i=0;i<m;i++)

{

cin>>a[i];

if(a[i]>0x39||a[i]<0x30)

{a[m-1]=i;break;}

}//输入第M步:字符数组以非数字结尾

for(i=0;i<a[m-1];i++)

b[i]=int(a[(a[m-1]-1-i)]-0x30);//转换成十进制整型数组,个位在b[0]

multwo(d,m,n);

cout<<endl;

cout<<"step max: ";

j=0;

for(i=m-1;i>=0;i--)

{

if(d[i]==0&&j==0) continue;

j=1;

cout<<d[i];

}

cout<<"-1"<<endl;

for(i=m-1;i>=0;i--)

{

if(b[i]<d[i]) break;

if(b[i]>d[i]||(b[i]==d[i]&&i==0))

{cout<<"step err! (step>=2^disk)"

<<endl; return;}

}//输入第M步是否<=2^disk-1

for(i=0;i<m;i++)

{

d[i]=b[i];e[i]=b[i];

}

for(i=0;i<n;i++)

{

if(b[0]%2==1) { c[i]=1;b[0]-=1;}

else c[i]=0;

for(j=0;j<m;j++) if(b[j]!=0) break;

if(j==m) break;

divtwo(b,1+n/2);

}

cout<<" ";

for(i=n-1;i>=0;i--)

{

cout<<c[i]<<" ";

}//step的n位二进制数组表示

cout<<endl;

j=0;

int aa1=0,bb1=0,cc1=0,dd1=0;

if(c[n-1]==0) { aa[aa1]=n;aa1++;dd1=1;}

else { cc[cc1]=n;j++;cc1++;dd1=3;}

for(i=n-2;i>=0;i--)

{

if(c[i+1]==c[i])

{

switch(dd1)

{

case 1: { aa[aa1]=i+1;aa1++;

dd1=1;continue;break;}

case 2: { bb[bb1]=i+1;bb1++;

dd1=2;continue;break;}

case 3: { cc[cc1]=i+1;cc1++;

dd1=3;continue;break;}

}

}

else

{

j++;

switch(dd1)

{

case 1: if(j%2==i%2) {cc[cc1]=i+1;

cc1++;dd1=3;continue;break;}

else { bb[bb1]=i+1;bb1++;

dd1=2;continue;break;}

case 2: if(j%2==i%2){aa[aa1]=i+1;

aa1++;dd1=1;continue;break;}

else {cc[cc1]=i+1;cc1++;

dd1=3;continue;break;}

case 3: if(j%2==i%2) {bb[bb1]=i+1;

bb1++;dd1=2;continue;break;}

else { aa[aa1]=i+1;aa1++;

dd1=1;continue;break;}

}

}

}// 根据step的n位二进制数组表示,解出A、B、// C柱上各金片的相对排列。

for(i=0;i<n;i++)

{

if(d[0]%2==1)

{

divtwo(d,1+n/2);

decaddone(d,m);

cout<<"disk: "<<n<<" "<<"step: ";

k=0;

for(j=m-1;j>=0;j--)

{

if(e[j]==0&&k==0) continue;

k=1;

cout<<e[j];

}

cout<<endl;

cout<<"No. "<<i+1<<" "

<<"times: ";

k=0;

for(j=m-1;j>=0;j--)

{

if(d[j]==0&&k==0) continue;

k=1;

cout<<d[j];

}

if(d[0]==0&&k==0) cout<<d[0];

cout<<" ";

k=0;

for(j=0;j<m;j++)

{

k+=d[j];

}

if(n%2==(i+1)%2)

{

switch(k%3)

{

case 0: cout<<"B------>A"

<<endl; break;

case 1: cout<<"A------>C"

<<endl; break;

case 2: cout<<"C------>B"

<<endl; break;

}

}

else

{

switch(k%3)

{

case 0: cout<<"C------>A"

<<endl; break;

case 1: cout<<"A------>B"

<<endl; break;

case 2: cout<<"B------>C"

<<endl; break;

}

}

break;

}

else divtwo(d,1+n/2);

}//根据上文提到的数学表达式(2^i)*(2^j-1)=M计算

cout<<"A ";

for(i=n-1;i>=0;i--)

{

if(n%2==1&&c[n-1]==1)

cout<<bb[i]<<" ";

else cout<<aa[i]<<" ";

}

cout<<endl;

cout<<"B ";

for(i=n-1;i>=0;i--)

{

if(n%2==1)

if(c[n-1]==1) cout<<aa[i]<<" ";

else cout<<cc[i]<<" ";

else cout<<bb[i]<<" ";

}

cout<<endl;

cout<<"C ";

for(i=n-1;i>=0;i--)

{

if(n%2==1&&c[n-1]==0)cout<<bb[i]<<" ";

else cout<<cc[i]<<" ";

}

cout<<endl;

//求解出A、B、C柱上各金片的最终排列。

}

/*****************非递归算法******************

* 本例输入:disk为金片数(1~100)。

* step为移动的第xxxx步。

* xxxx应小于2^disk。

* 本例输出:第xxxx步为第xx金片第xxxx次移动。

* 且是从x柱移动到x柱。

* 注: A源柱,B桥柱,C目的柱。

* 另注: 例共1张金片,其移动步骤可能是:第

* 1步从A>B,第2步从B-->C。但这不是我们

* 要的答案!正确方法是:第1步从A>C。

*****************程序运进结果*****************

输入:4 10p(非数字结尾)

输出:step max: 16-1

1 0 1 0(10的4位二进制表示)

disk:4 step:10

No. 2 times:3 B--àA

A 0 0 0 2

B 0 0 0 3

C 0 0 1 4

解析:共4张金片的第10步为:

第2张金片第3次移动,且是从B柱上移动到A柱上。

*********************************************/

#27
denglei_3182006-04-14 14:23

厉害

#28
ElfDN2006-04-14 23:39

大家都那么出力,我也灌一下,原创的1维的LCS(最长公共子序列)
#include<iostream>
#include<vector>
using namespace std;
int main(){
for(string s1,s2; cin>>s1>>s2; ){
int temp,temp1,l1=s1.length(),l2=s2.length(),mx=0;
vector<int> sign(l2,0);
for(int i=0; i<l1; i++){
temp=temp1=0;
for(int j=0; j<l2; j++){
if(sign[j]>temp1) temp1=sign[j];
if(s1[i]==s2[j]){
sign[j]=temp+1;
if(sign[j]>mx) mx=sign[j];
}
if(temp1>temp) temp=temp1;
}
}
cout<<mx<<endl;
}
}

#29
3037709572006-04-15 20:19
确实是好帖子!
#30
N9monster2012-02-24 09:39
谢谢分享
#31
麦迪依然2012-04-21 10:10
真不错!
#32
baliguo12013-04-27 07:39
回复 楼主 live41
不错不错啊
1