您的位置:首页 > 编程语言 > C语言/C++

[ 算法]经典程序算法问题

2006-10-27 17:39 507 查看
 经典矩形问题

生成各种矩阵是竞赛时经常考的一种题目,如何用C语言或C++生成以下形式几种矩阵:

第一种矩阵:

1 2 9 10
4 3 8 11
5 6 7 12
16 15 14 13

第二种矩阵蛇形)

1 2 6 7
3 5 8 13
4 9 12 14
10 11 15 16

第三种矩阵:

1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7

第四种矩阵:

7 6 5 16
8 1 4 15
9 2 3 14
10 11 12 13

规律提示:

1.1->2 9->10
4<-3 8 11
5->6->7 12
16<-15<-14<-13
2.每个左上三角的数都是连续的
3.一个回旋阵,从外到里是连续的。
4.同样是回旋,从里到外是连续的。

第一种矩阵算法:

#include<iostream.h>
#include<iomanip.h>

void main()
{
const int N=20;
int i=0,j=0,a

;
int lap=1,m=1,n;
while(1)
{
cout<<"/ninput matrix row N(N>=2): ";
cin>>n;
cout<<endl;
if(n>=2) break;
}
a[j]=m++;
lap++;
while(lap<=n)
{
if(lap%2==0)
{
for(j++;i<lap;i++)
a[j]=m++;i--;
for(j--;j>=0;j--)
a[j]=m++;j++;
}
else
{
for(i++;j<lap;j++)
a[j]=m++;j--;
for(i--;i>=0;i--)
a[j]=m++;i++;
}
lap++;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
cout<<setw(4)<<setiosflags(ios::left)<<a[j];
cout<<endl;
}
cout<<endl;
}

第二种矩阵算法:(蛇形)

#include<iostream.h>
#include<iomanip.h>

void main()
{
const int MAXLEN=10;
int nLen;
int nSnake[MAXLEN][MAXLEN];
do
{
cout<<"/ninput an integer less then "<<MAXLEN<<": ";
cin>>nLen;
cout<<endl;
}while(nLen>MAXLEN);
int i=0,j=0,s=1,nNum=1;
//s标记升降方向,斜向上为升(s==1),斜向下为降(s==-1)
while(1)
{
if(s==1)
{
nSnake[j]=nNum;
if(i-1<0)
{
if(j+1==nLen)
i++;
else
j++;
s=-1;
}
else
if(j+1==nLen)
{
i++;
s=-1;
}
else
{
i--;
j++;
}
}
else
{
nSnake[j]=nNum;
if(j-1<0)
{
if(i+1==nLen)
j++;
else
i++;
s=1;
}
else
if(i+1==nLen)
{
j++;
s=1;
}
else
{
i++;
j--;
}
}
nNum++;
if(nNum>nLen*nLen)
break;
}
for(i=0;i<nLen;i++)
{
for(j=0;j<nLen;j++)
cout<<setw(4)<<setiosflags(ios::left)<<nSnake[j];
cout<<endl;
}
cout<<endl;
}

第三种矩阵算法:

#include<iostream.h>
#include<iomanip.h>

void main()
{
const int N=20;
int i=0,j=0,a

,n;
int m=1,x1,x2,y1,y2,s=1;
//x1,x2,y1,y2为上、下、左、右边界
//s标记数组元素升降,s==1为升,s==-1为降
while(1)
{
cout<<"/ninput matrix row N(N>=2): ";
cin>>n;
cout<<endl;
if(n>=2)
break;
}
x1=0;y1=0;x2=n;y2=n;
while(1)
{
if(s==1)
{
for(j;j<y2;j++)
a[j]=m++;
j--;i++;y2--;
for(i;i<x2;i++)
a[j]=m++;
i--;j--;x2--;
s=-1;
}
else
{
for(j;j>=y1;j--)
a[j]=m++;
j++;i--;y1++;
for(i;i>=x1+1;i--)
a[j]=m++;
i++;j++;x1++;
s=1;
}
if(m>n*n)
break;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
cout<<setw(4)<<setiosflags(ios::left)<<a[j];
cout<<endl;
}
cout<<endl;
}

第四种矩阵算法:

#include<iostream.h>
#include<iomanip.h>

void main()
{
const int N=20;
int i=0,j=0,a

,n;
int m,x1,x2,y1,y2,s;
//x1,x2,y1,y2为上、下、左、右边界
//s标记数组元素升降,s==1为升,s==-1为降
while(1)
{
cout<<"/ninput matrix row N(N>=2): ";
cin>>n;
cout<<endl;
if(n>=2)
break;
}
m=n*n;
x1=0;y1=0;x2=n;y2=n;
if(n%2==0)
{j=n-1;y2=n-1;s=1;}
else
{i=n-1;y1=1;s=-1;}
while(1)
{
if(s==1)
{
for(i;i<x2;i++)
a[j]=m--;
i--;j--;x2--;
for(j;j>=y1;j--)
a[j]=m--;
j++;i--;y1++;
s=-1;
}
else
{
for(i;i>=x1;i--)
a[j]=m--;
i++;j++;x1++;
for(j;j<y2;j++)
a[j]=m--;
j--;i++;y2--;
s=1;
}
if(m<1)
break;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
cout<<setw(4)<<setiosflags(ios::left)<<a[j];
cout<<endl;
}
cout<<endl;
}
八皇后问题

通过创建一个8元素数组queenlist,递归函数placeQueen()具体执行此回溯算法。此数组的每个索引值都对应着棋盘上的一列,queenlist[col]值就是皇后所处的安全行数row。下面程序声明一个棋盘board,再使用setQueens()函数确定皇后再棋盘上8个安全位置。最后调用drawBoard()函数再棋盘上显示答案。
//文件:prg15——6.cpp
//此程序可以解决八皇后问题。程序提示用户输入皇后在0列的起始行并调用递归函数
//queens()确定是否有解决方案。如果有则将皇后的位置传到chessboard对象board
//并调用其drawBoard()函数显示皇后的布置。
#include<iostream.h>
#include”d_queens.h”
using namespace std;
int main()
{
int row;
vector<int>queenlist(8);
chessboard board;
//为0列皇后输入起始行
cout<<”Enter row for queen in column 0:”;
cin>>row;
cout<<endl;
//查看是否有解决方案
if (queens(queenlist, row))
{
board.setQueens(queenlist);
//显示解决方案
board.drawBoard();
}
else
cout<<”No solution”<<endl;
return 0;
}
第一次运行结果

0 1 2 3 4 5 6 7

0 Q

1 Q

2Q

3 Q

4 Q

5 Q

6 Q

7 Q

第二次运行结果

0 1 2 3 4 5 6 7

0 Q

1 Q

2 Q

3

4 Q

5Q Q

6 Q

7 Q费尔马“二平方”素数

除了2这个特别的素数外,所有的素数都可以分成两类:第一类是被4除余1的素数,如5,13,17,29,37,41;第二类是被4除余3的素数,如3,7,11,19,23,31。第一类素数都能表示成两个整数的平方和(第二类不能),例如:5=1*1+2*2、13=2*2+3*3、17=1*1+4*4、29=2*2+5*5...这就是著名的费尔马“二平方”定理。有趣的是:上述等式右侧的数有的又恰恰是两个素数的平方,如13、29,我们就把这样的素数叫作费尔马“二平方”素数,即是如果一个素数能够表示成两个素数的平方和的形式,例如:F=X*X+Y*Y (1),其中F、X、Y都是素数,它就是费尔马“二平方”素数。

编程思路:

本文拟用C++编程,求42亿之内(本人只算了10万以内的)的费尔马“二平方”素数。如果按定义从左向右,先求一个素数F,然后再去找相应的素数X、Y,工作量重复太大。我们可以对上述公式进行分析:
1、左侧素数F肯定是奇数,那么右侧两个素数的和也应该是奇数,所以X和Y为一奇一偶(奇数的平方还是奇数,偶数的平方还是偶数)。X、Y要求是素数,而既是偶数又是素数的数只有一个——2,这样我们就可以确定其中一个为2(这里设X=2)。所以(1)式可以简化为:F=2*2+Y*Y (2),费尔马“二平方”素数的表示形式是惟一的。
2、按(2)式由大到小找素数Y,计算出加上4(2*2)后是否等于F,判断其是否素数。
3、求出素数Y后将其保存起来,在判断其它数是否素数时可直接用已求出的素数去除,如此反复。

算法源代码如下:

#include<iostream.h>
#include<iomanip.h>

unsigned int a[10000],n=0,c=0;
//prime array,match counter,array counter

void ScreenOut(unsigned long int prime)
{
unsigned int p;
for(p=c-1;p>0;p--) //from the front one
if(prime==(a[p]*a[p]+4))
{
//cout<<'/n';
cout<<setw(5)<<prime<<" = 2*2 + "<<setw(3)
<<a[p]<<" * "<<setw(3)<<a[p]<<endl;
n++;
}
}

void main()
{
unsigned long int i,count,quantity=100000;
int judgement; //if the number is prime,assign 1
a[0]=2;
for(count=3;count<quantity;count+=2)
{//because odd,jump 2 steps once
judgement=1; //assign 1 every cycle
for(i=3;i<count/2;i++)
{
if(count%i==0)
{
judgement=0;
break;
}
}
if(judgement)
{
a[++c]=count; //if prime,assign to array
ScreenOut(count);
}
}
cout<<"/ntotal of match: "<<n<<'/n'<<endl;
}

结论:

运行程序会发现,除“29=2*2+5*5”以外,算出来的所有的费尔马“二平方”素数个位数字都是3,相应Y的个位数字都是3或7。费尔马“二平方”素数分布(修改程序中变量x的值得到)也很耐人寻味...(部分省略)

费尔马“二平方”素数太少了,40亿内才718个(本人的电脑CPU慢,只算了10万以内的,符合条件的也就只有20个),千万分之二还不到呢。随着数的范围的增大,似乎越来越稀少,但再往后永远是这样吗?会不会在某个范围内反而又稠密起来呢?费尔马“二平方”素数是无穷多个呢,还是有限多个呢?如果是有限个,又是多少个呢?最大的一个又是什么数呢?这些问题的证明可能很简单,也许很复杂,真说不定会成为像“哥德巴赫猜想”那样的谜呢!
无厘头字母题

输入一系列单字,直到文件尾,将每个字转换为Pig-latin语,如果单字以辅音字母开头,则将其第一个字符移到最后一个位置并在结尾增加"ay"。如果单字是以元音字母开头的,则直接在尾部加上"ay"。列如:
输入:this is simple
输出:histay isay implesay

# include <iostream>
# include <cstdlib>
# include <cstring>
using namespace std;

void changeWord(char* a, char* b);
int yWordcmp(char a);
int main()
{
const int SIZE = 50;
char iWord[SIZE];
char oWord[SIZE];
for (int i = 0; i<SIZE; i++)
{
iWord[0]=NULL;
oWord[0]=NULL;
}
cout<<"输入要转化 Pig-latin 语:/n";
cin.getline(iWord,SIZE);
changeWord(iWord,oWord);
cout<<"/n转换结果:/n"<<oWord<<endl;
system("pause");
return 0;
}

void changeWord(char* a, char* b)
{
char c = NULL;
while (*a != NULL)
{
while (! isalpha(*a))
*b++ = *a++;

c = yWordcmp(*a)? NULL : *a++;

while (isalpha(*a))
*b++ = *a++;
if(c) *b++ = c;
*b++ = 'a';
*b++ = 'y';
}
}

int yWordcmp(char a)
{
char yWord[5] = {'a','e','u','i','o'};
for (int i =0; i<5; i++)
{
if ((a == yWord)||(a == yWord-32))
return 1;
}
return 0;
}
年历的问题

历法系统我们一直都在使用,它在国际商务和交流中有着广泛的应用,它是罗马教皇格利高里的历法系统。罗马教皇, 主教, 蒲柏颁布的在基督教领域里使用的历法。它存在两个问题,第一个是这个世界绝大多数不是基督教。第二,基督教历法事实上是基于早期的历法系统(朱利安罗马皇帝的系统),它本身是从古代以及其他的一些历法演变过来的。为了把它推广到世界其他国家和宗教,它包含了很多有趣的东西来吸引人们。这学期我们来看一下法国的历法革命。
法国历法革命(共和历法)是在1793年11月24提出的。原因是为什么一部分人(包括法国人)直到1806年1月还没有听说这套历法系统已将废止了。而且在1871年又从新出现了,但是又一次的不显著死亡。法国历法革命有趣的地方是他极力的使用十进制。

共和国的历法八一年365天或366天分成12个月,每个月30天,再加上另外的5或6天。这些月份是
1,Vendemiaire
2,Brumaire
3,Frimaire
4,Nivose
5,Pluviose
6,Ventose
7,Germinal
8,Floreal
9,Prairial
10,Messido
11,Thermidor
12,Fructidor

这套系统不是把一周分为7天,它把一个月分成3个10天,其中10天的最后一天休息。尽管10天的制度很简单,但是9天工作一天休息的制度不是很流行,然而罗马教皇 Gregory 的工作6天休息一天似乎更流行。
这10天分别叫做:Primidi,Duodi,Tridi,Quartidi,Quintidi,Sextidi,Septidi,Octidi,Nonidi,Decadi.

额外的5或6天(365or366-12*30)接着果月(法国共和历的12月,相当于公历8月18 日到9月16日)的最后一天叫
1,Jour de la vertu (Virtue Day)
2,Jour du genie(Genius Day)
3,Jour du travail(Labour Day)
4,Jour de I’opinion(Reason Day)
5,Jour des recompenses(Rewards Day)
6,Jour de la revolution(Revolution Day)(the leap day)

法国共和历是从1792年9月22实施的。这一天变成了1 Vendemiaire共和历的第一年,(事实上这套历法直到1973年11月24才被介绍)。闰年的新年那一天被定在秋分(出现在9月22在北半球)为了精确,闰年与罗马教皇 Gregory 的历法系统一样每4年一次闰年(百年除了能被400整除的)。
计算闰年开始于法国共和历法20年后但是历法没有计算。法国共和历的前20年里,3,7和11时润年15和20也是 闰年,除了这些以后每4年一次闰年。(包括合适的百年)。

你的任务
作业目的把罗马教皇 Gregory 的历法(即:现在所用的阳历)换成法国共和历用C++程序。你可以用任何C++的class,建造或ADT等

有很多方法去完成作业
1,开始输入阳历
2,基于这些数字,求出自共和历建立以来的天数。
3,基于这些数字,求出自共和历建立以来的月数和年数。
4,最后得出相应的共和历日期

最初的界面提示如下:
Please enter a Gregorian date (dd mm yyyy):
程序输出法国共和历的日期格式:[day][month name][year],例如:6 Nivose 49.因为输入的是阳历,有365或366天,而我们要得出的是共和历,但共和历只有30*12=360天,所以多出的5,或6天我们就用以上给出的共和历提供给我们的那几种名称来取代(例如:Jour du genie).如果输入的阳历在共和历之前(即1792年9月22日之前),那么输出就使用BR(before republic),意思就是共和历前多少日期。如果共和历日期显示在屏幕上,那么程序宣告终止。

以下是测试程序是否正确,它们是阳历的新年(1月1日)在共和历里的日期
year 1: 22 sep 1792
year 5: 22 sep 1796
year 10: 23 sep 1801
year 12 :24 sep 1803

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息