目录
迭代:(辗转法) 一种 不断用变量的旧值递推新值的过程
【例3-1】 输出如图的杨辉三角形。
【例3-2】穿越沙漠问题
【例3-2】内存移动问题
【例3-4】编程求当n<=100时,n!的准确值。
代码
分类:
设计方法:
斐波那契:
例如二路归并
快排
输入情况:
每个输入, 划分的比较次数都是n-1。(每个元素都要跟首元素进行比较)
工作量总和:(比较次数)
差消化简:
存储:A[n,n]矩阵
矩阵:A = {a0,0,a1,0,a1,1,…,ai,0,…,ai,i,…,an-1,n-1}
//元素之间的关系:ai,j=ai-1,j-1+ai-1,j 即当前元素的值,是由上一层同列和上一层同列左侧的元素相加得到。
算法设计与描述 | 算法分析 |
输入: n | (1)输入n ,规模为n |
输出:杨辉三角 | |
Yanghui(n) { a[0,0] <- 1,a[1,0]<-1 ,a[1,1]<-1; //3 for i <- 2 to n-1 do { a[i,0]<- 1 ;a[i,i] <- 1; //2 for j<- 1 to i-1 do a[i,j] <- a[i-1,j-1]+a[i-1,j]; // 1 } output(a); } |
(2)核心操作:a[i,j] <- a[i-1,j-1]+a[i-1,j]的加法运算及两边的值 |
杨辉三角与斐波那契数列:
// 1.车到达终点时油箱是空的。2.路上的每一个中转点都没有剩下油。
从i-1点往i点运油时,最节省的情况是从i-1点出发时应该油箱装满油,然后在i点放下油后回到i-1点时油箱是空的,这时候运油的效率是最高的。
- dis1=500 //终点到第一加油站的距离
- oil1=500 //第一加油站的油量
- dis(n)= dis(n-1) + 500/(2*n-1) 约束:dis(n-1)
- oil(n) = oil(n-1)+500 //下一个加油站的油量多500 也可以用500*i
算法设计与描述 | 算法分析 |
输入: distance | (1)输入distance |
输出:每个加油站的油量 及 到终点的距离 | 规模 distance 与n |
Desert ( distance ) { dis <- 500,oil <- 500,n <- 1;
} |
(2)核心语句:求加油站的距离 规律如下 500 + 500/3 + 500/5 +...+ 500/(2*n-1)=distance |
- 设数列中元素n个,向右移动 k 次 , 位置编号 0... n-1 。
- 按照(3-1)计算位置:
- Loc1 :x1 =(x0+k) mod n ,设商为y0 , x1=k+x0 - n*y0 ;
- Loc2 :x2 =(x1+k) mod n ,设商为y1 , x2= 2*k+x0 - n*(y0 +y1) ;
- Loc i:xi = (x (i-1) +k)mod n,设商为y(i-1) , xi = i*k +x0-n*(y0+...y(i-1));
- xi= ( x0 +i*k )mod n
- 设第i次连续移动后,回到初始位置,则一定有 xi = (x0 + i*k ) mod n = x0 (式3-3)
- 设第m论连续移动的起始位置为xm ,则有:xi=(xm+i*k )mod n = xm ;
- 必须有 i*k mod n =0 成立。
- 所以可设:i*k/n = y -> i*k = n*y
- 设k与n的最大公约数Q ,则有 k=a*Q , n=b*Q ,可得 k/n = y/i = (a*Q)/(b*Q) , a,b互质【不互质 就不是最大公约数,,ab就是另一个约数/因数】
计算模型:
(1) 求最大公约数— 欧几里得定理 (辗转相除), 当 r≠0 时,有
- r=a mod b (3 − 5 )
- gcd ( a, b ) = gcd ( b, r ) r≠0 (3 − 5 )
(2) 令 Q=b , 移动次数: i =n/Q
(3)计算元素移动位置: m = (m+k ) mod n 【 (3 - 2),(3 - 4) 】
算法设计与描述 | 算法分析 |
输入: n, k ,n个元素的数列 | |
输出:向右移动 k 位的数列 | |
最大公约数: Euclid (a,b) { temp <- a%b; while temp do a=b; b=temp; temp=a%b; return b;//最大公约数 } |
f(b) = log1.618( b * 根5 ) |
Memory_move(n,k,a[n]) { Q <- Euclid (n,k); //求最大公约数 //例如 2 = Euclid(n=6,k=3); 分成2组 for( q <- 0 ; q < Q ; q <- q+1) //Q是移动轮数 { temp <- a[q]; //第一次循环 temp=a[0] m <- q; //下标 m=0 for(i <-0 ;i { m <- (m+k) mod n; //元素移动位置 m=(0+3)%6=3 s <- a[m]; //a[m]和temp交换 a[3]和a[0]交换 a[m] <- temp; // temp <- s; // } } |
(1)问题规模 是由元素个数n 及 移动次数k 控制 (2)核心语句:内层循环移动 (3)算法时间复杂度(移动次数): /* 第一次循环 q=0 temp=a[0] m=0 i 0 to 3 m= (0+3)%6=3 a[3]和temp即a[0]交换 temp=a[3] m=(3+3)%6=0 a[0]和a[3]交换 temp=a[0] m= (0+3)%6=3 a[3]和temp即a[0]交换 temp=a[3] 第二次循环 q=1 temp=a[q] = a[1] m=q=1 i 0 to 3 m= (m+k) mod n=(1+3)%6=4 a[4]和temp即a[1]交换 temp=a[4] m=(4+3)%6=1 a[1]和a[4]交换 temp=a[1] m= (m+k) mod n=(1+3)%6=4 a[4]和temp即a[1]交换 temp=a[4] 0 1 2 3 4 5 3 4 5 0 1 2 */ |
改进 i <- n/Q -1 ; p1 <- (m+ i*k) mod n ;temp <- a[p1] ; for ( i <- i-1 ;i>=0 ;i-- ) // 次数n/Q-1 { p2 <- ( m+i*k ) mod n; a[p1] =a[p2]; p1=p2; } a[p2]=temp; |
/* m=0 i =1 , p1=(0+1*3) mod 6 =3 ,temp=a[3]; 循环 i=0;p2=(0+0)%6=0 ,a[3]=a[0];p1=0 i--退出 a[0]=a[3] m=1; i=1;p1=4,temp=a[4] */ |
算法设计与描述 | 算法分析 |
输入: n, k ,n个元素的数列 | |
输出:向右移动 k 位的数列 | |
最大公约数: Euclid (a,b) { temp <- a%b; while temp do a=b; b=temp; temp=a%b; return b;//最大公约数 } |
f(b) = |
Memory_move(n,k,a[n]) { Q <- Euclid (n,k); //求最大公约数 //例如 2 = Euclid(n=6,k=3); 分成2组 for( q <- 0 ; q < Q ; q <- q+1) //Q是移动轮数 { temp <- a[q]; //第一次循环 temp=a[0] m <- q; //下标 m=0 for(i <-0 ;i { m <- (m+n-k) mod n; //元素移动位置 s <- a[m]; //a[m]和temp交换 a[m] <- temp; // temp <- s; // } } |
(1)问题规模 是由元素个数n 及 移动次数k 控制 (2)核心语句:内层循环移动 |
改进 i <- n/Q -1 ; p1 <- (m+ i*(n-k)) mod n ;temp <- a[p1] ; for ( i <- i-1 ;i>=0 ;i-- ) // 次数n/Q-1 { p2 <- ( m+i*(n-k) ) mod n; a[p1] =a[p2]; p1=p2; } a[p2]=temp; |
找到本轮移动最后一个元素的位置(而不是移动后的位置),从前往后进行覆盖性移动,减少移动次数。 |
#include
using namespace std;
int Euclid(int a,int b)
{
int r=a%b;
while(r)
{
a=b;
b=r;
r=a%b;
}
return b;
}
int main()
{
int a[6]={0,1,2,3,4,5};
int n=6,k=2;//前移
int q=Euclid(n,k);
for(int i=0;i
#include
using namespace std;
int Euclid(int a,int b)
{
int r=a%b;
while(r)
{
a=b;
b=r;
r=a%b;
}
return b;
}
int main()
{
int a[6]={0,1,2,3,4,5};
int n=6,k=2;//前移
int q=Euclid(n,k);
for(int i=0;i=0;j--)
{
p2=(i+j*(n-k) )%n;
a[p1]=a[p2];
p1=p2;
}
a[p2]=temp;
}
for(int i=0;i<6;i++)
{
cout<
竖式乘法原理--实例分析
计算模型:
其中,b表示每个数组元素相乘的实际结果,d是进位。
注意:输出时 补0 。
算法设计与描述 | 算法分析 |
输入: n | (1) |
输出:n! | 问题规模 是 n次乘法 |
Bigdigital (n) |
(2)核心语句:内层的竖式乘法 (3)算法时间复杂度是 |
#include
#include
using namespace std;
#define maxlen 34 //将数组长度近似设为(100!)所需数组长度
void output(long a[],int len)
{
int k;
for(int i=len;i>=1;i--)
{
if(a[i]==0) k=6;
else if(i==len)k=0;//最高位不需要补零
else k= 6 - ceil(log(a[i])) ;
for(int j=1 ;j>n;
int m= ceil(n*log(n)/6 );
long a[maxlen];//六位数 需要长整型
long b,d;//暂存
a[m]=0;
a[1]=1;
int len=1;//有效数组长度
for(i=2;i<=n;i++) //阶乘 从2到n
{
d=0;
for(j=1;j<=len;j++)//有效数组长度
{
b=a[j]*i+d;
a[j]=b % 1000000;
d=b/1000000;
}
if(d!=0)//需要进位
{
a[j]=d;
len++;
}
}
output(a, len);
return 0;
}
测试:100!
100
93
326215
443944
152681
699238
856266
700490
715968
264381
621468
592963
895217
599993
229915
608941
463976
156518
286253
697920
827223
758251
185210
916864
000000
000000
000000
000000
/*
unsigned int 0~4294967295
int -2147483648~2147483647
unsigned long 0~4294967295
long -2147483648~2147483647
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:18446744073709551615
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
*/
考虑到数的位数不确定,所以采用string字符串存储。从最低位开始逐位相乘处理进位 注意需要进行字符和数字的转换,一定要转换。
两大数字符串为a,b,存储乘积结果的字符串为sum。其中temp 暂存结果 jin存进位。
temp <- (sum[i+j]-'0'+(a[i]-'0')*(b[j]-'0')+jin); (0<=i<=a.size()-1,0<=j<=b.size()-1)
sum[i+j]<-temp%10+'0';
jin<-temp/10;
算法设计与描述 | 算法分析 |
输入: a,b | (1) |
输出:sum | 问题规模 是 a.size()*b.size()次运算 |
zhuwei(a,b) temp <- (sum[i+j]-'0'+(a[i]-'0')*(b[j]-'0')+jin); sum[i+j]<-temp%10+'0'; jin<-temp/10; jin<-jin/10; for(i<-0;i { cout< |
(2)核心语句:内层的竖式乘法 (3)算法时间复杂度是 /* 假设其中较大的数为b */ |