**

算法概述

**
经典算法:
穷举搜索算法:floyed算法
迭代算法:数学函数的迭代求解
递推算法:斐波那契数列
递归算法:汉诺塔
分治算法:快速排序,折半查找等
贪心算法:最小代价生成树
动态规划算法:
回溯算法:图的深度优先算法
分支限界算法:以广度优先搜索为基础,定义剪枝策略

**

递推算法

1 . 求菲波那契数列的前 n 项*
Fibonacci 数列:0,1,1,2,3,5,8,13,21,34,……
f0 = 0
f1 = 1
fn = fn-1 + fn-2 ( n >= 2 )
分析:为了得到当前项,要使用前两项,所以用两个变量迭代
代码:
#include
using namespace std ;
int main(){
int n, i, a0, a1 ;
cout << "n = " ;
cin >> n ;
a0 = 0 ; a1 = 1 ;
cout << a0 << " "<< a1 << " ";
for ( i = 2; i <= n/2 ; i ++ ){
a0 = a0 + a1 ;
a1 = a1 + a0 ;
cout << a0 << " "<< a1 << " ";
if ( i % 5 == 0 ) cout << endl ;
}
if ( n > (i-1)2 ) cout << a0+a1 << endl ;
return 0;
}
2. 求 N 层汉诺塔的移动次数
递推关系分析
f(n)=2
f(n-1)+1
边界条件:f(1)=1
代码
#include
using namespace std;
int main(){
int f[1000]={0,1};
int n;
cin>>n;
for(int i=2;i<=n;i++)
f[i]=2f[i-1]+1;
cout<<f[n]<<endl;
return 0;
}
3. 猴子吃桃
递推关系:
f(n)=f(n-1)/2-1
f(n-1)=(f(n)+1)2
边界条件:f(10)=1
代码:
#include
using namespace std;
int main(){
int f[11];
f[10]=1;
for(int i=9;i>=1;i–)
f[i]=2
(f[i+1]+1);
cout<<f[1]<<endl;
return 0;
}
4 数字三角形。
算法设计笔记
代码:
#include
#include
using namespace std;
const int MAXN = 1005;
int A[MAXN][MAXN],F[MAXN][MAXN],N;
int main() {
cin >> N;
for(int i = 1;i <= N;i ++)
for(int j = 1;j <= i;j ++)
cin >> A[i][j];
F[1][1] = A[1][1];
for(int i = 2;i <= N;i ++)
for(int j = 1;j <= i;j ++)
F[i][j]=max(F[i-1][j-1],F[i-1][j])+A[i][j];
int ans =0;
for(int i = 1;i <= N;i ++)
ans = max(ans,F[N][i]);
cout << ans << endl;
return 0;}
5. 走台阶
递推关系分析:
f[i]=f[i-1]+f[i-2]+…f[i-k] 其中:( i>=j ,j>=1 && j<=k)
递推的边界条件(已知值):f[0]=1.
#include
#include
#include
using namespace std;
int main(){
int n, k;
int f[100001] = { 0 };
cin >> n >> k;
f[0] = 1; //初始值,边界条件
for (int i = 1; i <= n; i++) {
for (int j = 1; j <=k; j++) {
if (i - j >= 0) {
f[i] += f[i - j];
f[i] = f[i] % 100003;//注意要取模
}
}
}
cout << f[n];
return 0; }
6. 蜜蜂路线
算法分析:
f[]:爬到i位置的方法数
递归关系分析:
f[i]=f[i-1]+f[i-2]
递推边界:
f[m]=1(爬行起点方法数为0)
f[m+1]=1(爬行起点到达相邻的下一个蜂巢的爬行方法数为1)
代码:
#include
#define SIZE 15001
using namespace std;
int f[SIZE] ;
int main(){
int n, m, i;
cin >> m >> n;
f[m]=1;
f[m+1]=1;
for (i = m+2; i <= n; i++)
f[i] = f[i-1] + f[i-2];
cout << f[n] << endl;
return 0;
}
7. 吃糖果
算法分析:
如果N=1,则名名第1天就吃掉它,共有1种方案;
如果N=2,则名名可以第1天吃1块,第2天吃1块,也可以第1天吃2块,共有2种方案;
如果N=3,则名名第1天可以吃1块,剩2块,也可以第1天吃2块剩1块,所以名名共有2+1=3种方案;
如果N=4,则名名可以第1天吃1块,剩3块,也可以第1天吃2块,剩2块,共有3+2=5种方案。
f[i] = f[i - 1] + f[i - 2]
代码:
#include
using namespace std;
int main(){
int f[20] = {0};
f[1] = 1; f[2] = 2;
for (int i = 3; i <= 20; i++){
f[i] = f[i - 1] + f[i - 2];
}
int n;
while (cin >> n){
cout << f[n] << endl;
}
return 0;
}
8 . 昆虫繁殖
分析:
定义数组f,f[i]表示第i月昆虫成虫的数量
添加一个辅助数组b,b[i]表示第i月的卵的数目,从而得到两个公式:
b[i] = f[i - x] * y; (成虫经过x月产卵 y对)f[i] = f[i - 1] + b[i - 2]; (卵经过2个月长成成虫)
代码:
#include
using namespace std;
int main(){
long long a[101]={0},b[101]={0},i,j,x,y,z;
cin>>x>>y>>z;
for(i=1;i<=x;i++){
a[i]=1;
b[i]=0;
}
for(i=x+1;i<=z+1;i++){ //因为要统计到第z个月后,所以要for到z+1
b[i]=y
a[i-x];
a[i]=a[i-1]+b[i-2];
}
cout<<a[z+1]<<endl;
return 0;
}
4. 位数问题
算法分析
前i位有偶数个3,必须满足以下条件:
前i-1位有偶数个3, 则 第i位不能取3
前i-1位有奇数个3,则第i位必须取3
可以用f[i][0]表示前i位取偶数个3有几种情况,
f[i][1]表示前i位取奇数个3有几种情况。
则递推公式可以表示为:
   f[i][0] =f[i-1][0]*9+f[i-1][1]; (9:除3 外的每一个数字)
f[i][1] =f[i-1][0] + f[i-1][1]*9; (9:除3 外的每一个数字)
边界条件: f[1][1]=1;f[1][0]=9;
代码:
#include
using namespace std;
int main(){
int f[1001][2],n,i,x=9;
cin>>n;
f[1][1]=1;f[1][0]=9;
for(i=2;i<=n;i++) {
if(in) // i是最高位
x–;
f[i][0]=(f[i-1][0]*x+f[i-1][1])%12345;
f[i][1]=(f[i-1][1]*x+f[i-1][0])%12345;
}
cout<<f[n][0];
return 0;
}
10.分苹果
分析
f(m,n) 为m个苹果,n个盘子的放法数目,则先对n作讨论,
当n>m:
必定有n-m个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响。即if(n>m) f(m,n) = f(m,m)  
当n<=m:不同的放法可以分成两类:
1、有至少一个盘子空着,即相当于
f(m,n) = f(m,n-1);
2、所有盘子都有苹果,相当于可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即
f(m,n) = f(m-n,n).
而总的放苹果的放法数目等于两者的和,即
f(m,n)=f(m,n-1)+f(m-n,n)
边界条件说明:
当n=1时,
所有苹果都必须放在一个盘子里,所以返回1;
当没有苹果可放时,
定义为1种放法;
#include
using namespace std;
int main(){
int m,n,dp[15][15]; //第一维表示苹果个数,第二维表示盘子个数
cin>>m>>n;
for(int i=0;i<=m;++i){ //初始化,盘子有0,1个时的方法数,
dp[i][0]=0;
dp[i][1]=1;
}
for(int i=0;i<=n;++i)
dp[0][i]=1; //苹果0个时,定义为1种情况
for(int i=1;i<=m;++i){ //i苹果个数
for(int j=1;j<=n;++j){ //盘子个数
if(i<j)
dp[i][j]=dp[i][i];
else
dp[i][j]=dp[i][j-1]+dp[i-j][j];
}
}
cout<<dp[m][n]<<endl;
return 0;
}
12 . 踩方格
算法分析:
每一步均可向上,向左,向右
以移动步数进行递推
代码:
#include
#include
using namespace std;
int n,ans; int l[30],r[30],u[30];
int main(){
cin>>n;
if (n
1) cout<<3;
else {
l[1]=1; r[1]=1; u[1]=1;
for (int i=2;i<=n;i++) {
l[i]=l[i-1]+u[i-1];
r[i]=r[i-1]+u[i-1];
u[i]=l[i-1]+r[i-1]+u[i-1];
}
ans=l[n]+r[n]+u[n]; cout<<ans<<endl;
}
return 0;
}


STL

STL的组成:
1)容器(Container)
2)迭代器(Iterator)
3)算法(Algorithm)
4)函数对象(Function object)
5)适配器(Adaptor)
6)空间配制器(allocator)

STL容器分为两类(这两者通过数据在容器内的排列来区分)
序列式容器
每个元素都有固定位置--取决于插入时机和地点,和元素值无关,
vector、deque、list;
关联式容器
元素位置取决于特定的排序准则,和插入顺序无关
set、multiset、map、multimap;

STL容器元素的条件:
必须能够通过拷贝构造函数进行复制
必须可以通过赋值运算符完成赋值操作
必须可以通过析构函数完成销毁动作
序列式容器元素的默认构造函数必须可用
某些动作必须定义operator ==,例如搜寻操作
关联式容器必须定义出排序准则,默认情况是重载operator <

迭代器持续有效,除非发生以下两种情况:
(1)删除或插入元素
(2)容量变化而引起内存重新分配

vector 和 数组的区别
1.array 定义的时候必须定义数组的元素个数;而vector 不需要;
2.array 定义后的空间是固定的了,不能改变;而vector 要灵活得多,可再加或减.
3.vector有一系列的函数操作,非常方便使用。
4.数组和vector不同,一个数组不能用另一个数组初始化,也不能将一个数组赋值给另一个数组;

map和set容器的共同点
内部由二叉树(二叉链表)实现,便于查找(这与set);
map和set容器的区别。
对于map中的每个节点存储的是一对信息,包括一个key和一个value ,各个节点之间的key的值(第一列的值)不能重复(重复的值自动删除)。
对于set中的每个节点存储的是一个信息,只有一个键,但是每个键值也是唯一的。set表示的是集合的概念。

map的构造函数:
map(); // 默认构造函数
map(const map& m) // 拷贝构造函数
map(iterator begin, iterator end ); //区间构造函数
map(iterator begin, iterator end, const traits& _compare) //带比较谓词的构造函数
等等

STL提供了三种容器适配器:stack,queue,priority_queue。
适配器并不是第一类容器,因为它们并没有提供与元素的保存形式有关的真正数据结构实现,并且适配器不支持迭代器。

优先队列的基本操作
empty() 如果队列为空返回真
pop() 删除对顶元素
push() 加入一个元素
size() 返回优先队列中拥有的元素个数
top() 返回优先队列对顶元素

头文件:#include
stack 模板类需要两个模板参数,一个是元素类型,一个容器类型,但只有元素类型是必要的,在不指定容器类型时,默认的容器类型为deque。
定义stack 对象的示例代码如下:
stack s1;
stack s2;
stack 的基本操作有:
入栈,如例:s.push(x);
出栈,如例:s.pop();注意,出栈操作只是删除栈顶元素,并不返回该元素。
访问栈顶,如例:s.top()
判断栈空,如例:s.empty(),当栈空时,返回true。
访问栈中的元素个数,如例:s.size()。

不可变序列算法(Non-mutating algorithms)
search算法
在一个序列中搜索与另一序列匹配的子序列。参数分别为一个序列的开始位置,结束位置和另一个序列的开始,结束位置。
函数原型:search(v1.begin(),v1.end(),v2.begin(),v2.end());
search_n算法(重复元素子序列搜索search_n)
函数搜索序列中是否有一系列元素值均为某个给定值的子序列。
函数原型:search_n(v.begin(),v.end(),3,8),在v中找到3个连续的元素8
最后一个子序列搜索find_end
函数原型find_end(v1.begin(),v1.end(),v2.begin(),v2.end());在V1中要求的位置查找V2中要求的序列。

可变序列算法(Mutating algorithms)
元素复制copy
copy(v.begin(),v.end(),l.begin());将v中的元素复制到l中。
元素变换transform
函数原型:transform(v.begin(),v.end(),l.begin(),square);也是复制,但是要按某种方案复制。
替换replace
replace算法将指定元素值替换为新值。
replace(v.begin(),v.end(), old,new);
条件替换replace_if
函数原型:replace_if(v.begin(),v.end(),odd,100);***

sort 算法
作用:以升序重新排列指定范围内的元素。重载版本使用自定义的比较操作
函数原型:
void sort(RanIt first, RanIt last)
void sort(RanIt first, RanIt last, Pred pr)
sort有以下特征:1. 要求输入一个范围[first, last)2. 随机迭代器,能用此算法的容器是支持随机访问的容器:vector, deque, string。3.第一个版本使用operator<进行比较,默认升序排序,第二个版本使用comp做比较.

**

递归与分治策略

递归需要有边界条件、递归前进段和递归返回段。
当边界条件不满足时,递归前进;
当边界条件满足时,递归返回。
注意:在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口,否则将无限进行下去(死锁)。
递归的缺点:
递归算法解题的运行效率较低。
在递归调用过程中,系统为每一层的返回点、局部变量等开辟了堆栈来存储。递归次数过多容易造成堆栈溢出等。

编写一个递归函数,将10进制转化成radix进制(输出二进制形式)
除基数,取余数,结果倒排序
void change(int x, int radix)
x, 十进制数,radix, 基数
根据除基数,取余数,结果倒排序的规则进行处理,直到商为0结束
代码:
#include
using namespace std;
void change(int a, int radix){
if(a!=0) {
change(a/radix,radix);
cout<<a%radix; //返回余数
}
}
int main(){
int x,radix;
cin>>x>>radix;
change(x,radix);
cout<<endl;
return 0;
}

集合全排列问题**
设计一个递归算法生成n个元素{r1,r2,…,rn}的全排列(n!种)。
设R={r1,r2,…,rn}是要进行排列的n个元素,
Ri=R-{ri}。
集合X中元素的全排列记为perm(X)。
(ri)perm(X)表示在全排列perm(X)的每一个排列前加上前缀得到的排列。
R的全排列可归纳定义如下:
当n=1时,
perm®=®,其中r是集合R中唯一的元素;
当n>1时,perm®由
(r1) perm(R1)
(r2) perm(R2)

(rn) perm(Rn)构成。

整数划分问题
最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,1): 最大加数不超过1的分解方法数
将最大加数n1不大于m的划分个数记作q(n,m)。

最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,2): 最大加数不超过2的分解方法数
=最大加数不超过1的分解方法数 q(6,1):;
+最大加数等于2的分解方法数 q(4,2):

最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,3) 最大加数不超过3的分解方法数
=最大加数不超过2的分解方法数 q(6,2):;
+最大加数等于3的分解方法数 q(3,3):

最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,4) 最大加数不超过4的分解方法数
=最大加数不超过3的分解方法数 q(6,2):;
+最大加数等于4的分解方法数 q(2,4):

最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,5) 最大加数不超过5的分解方法数
=最大加数不超过4的分解方法数 q(6,4):;
+最大加数等于5的分解方法数 q(1,5):

最大加数等于6: 6;
最大加数等于5: 5+1;
最大加数等于4: 4+2,4+1+1;
最大加数等于3: 3+3,3+2+1,3+1+1+1;
最大加数等于2: 2+2+2,2+2+1+1,2+1+1+1+1;
最大加数等于1: 1+1+1+1+1+1;
q(6,6) 最大加数不超过6的分解方法数
=最大加数不超过5的分解方法数 q(6,5):;
+最大加数等于6的分解方法数 q(0,6)
:
具体分析
q(n,m)=
q(n,m-1)+
q(n-m,m),n>m>1
q(n,m)=q(n,m-1)+q(n-m,m),n>m>1

  1. q(n,1)=?,n≥1;
    当最大数n1不大于1时,任何正整数n只有一种划分形式: n=1+1+…+1(共n个)。
  2. q(n,m)=? m≥n
    q(n,n);最大加数n1实际上不能大于n。因此,q(1,m)=1。
  3. q(n,n)=?
    1+q(n,n-1);正整数n的划分由n1=n的划分和n1≤n-1的划分组成。
  4. q(n,m)=? n>m>1
    q(n,m-1)+q(n-m,m),n>m>1;正整数n的最大加数n1不大于m的划分由n1=m的划分和n1≤m-1 的划分组成。

分治法的基本思想
1.分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。
2.对这k个子问题分别求解。如果子问题的规模仍然不够小,则再划分为k个子问题,如此递归的进行下去,直到问题规模足够小,很容易求出其解为止。
3.将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。

分治法所能解决的问题一般具有以下几个特征:
1.该问题的规模缩小到一定的程度就可以容易地解决;
2.该问题可以分解为若干个规模较小的相同问题
3.利用该问题分解出的子问题的解可以合并为该问题的解;
4.该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
分治策略的算法设计模式:
Divide_and_Conquer(P){
if (|P|<=n0 ) return adhoc§;
divide P into smaller substances P1,P2,…,Pk;
for (i=1; i<=k; k++)
yi=Divide-and-Conquer(Pi) //递归解决Pi
Return merge(y1,y2,…,yk) //合并子问题
}

二分搜索技术
给定已按升序排好序的n个元素a[0:n-1],现要在这n个元素中找出一特定元素x。
适用分治法求解问题的基本特征:
该问题的规模缩小到一定的程度就可以容易地解决;
该问题可以分解为若干个规模较小的相同问题;
分解出的子问题的解可以合并为原问题的解;
分解出的各个子问题是相互独立的。
很显然此问题分解出的子问题相互独立,即在a[i]的前面或后面查找x是独立的子问题,因此满足分治法的第四个适用条件。
给出若干个整数,询问其中是否有一对数的和等于给定的数.
输入:
4
2 5 1 4
6
输出
1 5
#include
#include
using namespace std;
int binsearch(int a[],int low,int high,int k){
int mid;
if(low>high)
return 0;
mid=(low+high)/2;
if(a[mid]==k)
return mid;
else if(k>a[mid])
return binsearch(a,mid+1,high, k);
else
return binsearch(a,low,mid-1, k);
}
int main(){
int i,n,a[1000],sum;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
cin>>sum;
for(i=1;i<n;i++) {
if(binsearch(a,i+1,n,sum-a[i])) {
cout<<a[i]<<" "<<sum-a[i]<<endl;
break;
}
}
return 0;
}

区间合并
思路1.
如果区间的端点范围很小,比如在范围[0,9999]。
可以开一个10000大小的bool数组,然后输入区间覆盖的范围都复制true。
则最后遍历数组,连续的true数据即为一个区间。
这种方法适用于区间范围小,区间的平均跨度不是很大
思路2.
首先,按区间的左端点排序
将要考察的区间分为二
考察
左区间能否合并
右区间能否合并
再考察在左右区间能否合并
最小规模的问题
一个区间可以合并
两个区间之间检查
#include
#include
using namespace std;
struct block{
int s,e;
};
bool cmp(block f, block e){
if (f.s<e.s)
return true;
return false;
}
block unionn(block b[], int f,int l){
if(f==l)
return b[f];
block temp1,temp2;
temp1=unionn(b,f,(f+l)/2);
temp2=unionn(b,(f+l)/2+1,l);
if(temp1.e>=temp2.s){
block temp;
temp.s=temp1.s;
temp.e=temp1.e>temp2.e?temp1.e:temp2.e;
return temp;
}
else{
block temp;
temp.s=0; temp.e=0; return temp;
}
}
int main(){
block b[10000],temp;
int n,i,s,e;
cin>>n;
for(i=1;i<=n;i++){
cin>>b[i].s>>b[i].e;
}
sort(b+1,b+n+1,cmp);
temp=unionn(b,1,n);
cout<<temp.s<<" "<<temp.e<<endl;
return 0;
}

循环赛日程表
#include
using namespace std;
#define MAX 100
int a[MAX][MAX];
void Copy(int tox, int toy, int fromx, int fromy, int r){
for(int i=0;i<r;i++)
for(int j=0;j<r;j++)
a[tox+i][toy+j]=a[fromx+i][fromy+j];
}
void Table(int k){ //k为分割次数。88,k=3;44,k=2
int i,r;
int n=1; //n为参赛人数
for(i=1;i<=k;i++)
n=n2;
for(i=0;i<n;i++)
a[0][i]=i+1;
//依次完成边长是1,2,4….n/2 的矩阵的复制
for(r=1;r<n;r=r
2)
for(i=0;i<n;i+=2*r) {//1次拷贝,通过多对(4,2,1)矩阵的拷贝完成
Copy(r, r+i, 0, i, r); //左上角拷贝到右下角
Copy(r, i, 0, r+i, r); //右上交角拷贝到左下角
}
}
int main(){
Table(3);
for(int i=0;i<=7;i++) {
for(int j=0;j<=7;j++)
cout<<a[i][j]<<" ";
cout<<endl;
}
return 0;
}

棋盘覆盖
整型二维数组Board表示棋盘,Borad[0][0]使棋盘的左上角方格。
tile是一个全局整形变量,用来表示L形骨牌的编号(放置骨牌的顺序号),初始值为0。
tr:棋盘左上角方格的行号;tc:棋盘左上角方格的列号;
dr:特殊方各所在的行号;dc:特殊方各所在的列号;
size:size=2k,棋盘规格为2k×2k。
void CB(int tr,tc,dr,dc,size){
if (size == 1) return;
int t = tile++; // L型骨牌顺序号
s = size/2; // 分割棋盘
// 处理左上角子棋盘
if (dr < tr + s && dc < tc + s) // 特殊方格在此棋盘中
CB(tr, tc, dr, dc, s);
else {
// 用 t 号L型骨牌覆盖右下角
board[tr + s - 1][tc + s - 1] = t;
// 覆盖其余方格
CB(tr, tc, tr+s-1, tc+s-1, s);
}
// 处理右上角子棋盘
if (dr < tr + s && dc >= tc + s)
// 特殊方格在此棋盘中
CB(tr, tc+s, dr, dc, s);
else {// 此棋盘中无特殊方格
// 用 t 号L型骨牌覆盖左下角
board[tr + s - 1][tc + s] = t;
// 覆盖其余方格
CB(tr,tc+s,tr+s-1,tc+s, s);
}
// 处理左下角子棋盘
if (dr >= tr + s && dc < tc + s)
// 特殊方格在此棋盘中
CB(tr+s, tc, dr, dc, s);
else {
board[tr + s][tc + s - 1] = t;
// 覆盖其余方格
CB(tr+s, tc, tr+s, tc+s-1, s);
}
// 处理右下角子棋盘
if (dr >= tr + s && dc >= tc + s)
// 特殊方格在此棋盘中
CB(tr+s, tc+s, dr, dc, s);
else {
board[tr + s][tc + s] = t;
// 覆盖其余方格
CB(tr+s, tc+s, tr+s, tc+s, s);}
}
T(k)=4k-1=O(4k) 渐近意义下的最优算法

快速排序的基本思想:
首先选第一个数作为分界数据,
将比它小的数据存储在它的左边,比它大的数据存储在它的右边,它存储在左、右两个子集之间。
这样左、右子集就是原问题分解后的独立子问题。
再用同样的方法,继续解决这些子问题,直到每个子集只有一个数据,就完成了全部数据的排序工作。

众数和重数
将第一个数作为轴值,对序列进行分割,得到两个子序列(不包括轴值),并统计出现次数cout
如果cout大于分割得到的两个子序列的长度,则该值即为众数;
如果左序列的长度大于count,则众数可能出现在左子序列中;
如果右序列的长度大于count,则众数可能出现在右子序列中;
#include
using namespace std;
struct mdata{
int data;
int count;
};
void msort(int a[], int s, int e, mdata &result){
int left,right,middle,count=1;
left=s;right=e;middle=(s+e)/2; int temp=a[left];
while(left<right){
while(a[right]>=temp){
if(a[right]==temp) count++;
right–;
}
if(left<right) a[left]=a[right];
while(a[left]<temp){
if(a[left]==temp) count++;
left++;
}
if(left<right) a[left]=a[right];
}
a[right]=temp;
if(count>result.count){result.count=count; result.data=temp; }
if(right-s>result.count) msort(a,s,right-1, result);
if(e-right>result.count) msort(a,right+1,e,result);
return ;
}
int main()
{
mdata result={0,0};
int a[10]={2,1,3,2,5,2,3,3,3,3};
msort(a,0,9,result);
cout<<result.data<<" "<<result.count<<endl;
return 0;
}

输油管道问题
算法1:对数组a排序(一般是升序),取中间的元素
int n; //油井的数量
int x; //x坐标,读取后丢弃
int a[1000]; //y坐标
cin>>n;
for(int k=0;k<n;k++)
cin>>x>>a[k];
sort(a,a+n); //按升序排序
//计算各油井到主管道之间的输油管道最小长度总和
int min=0;
for(int i=0;i<n;i++)
min += (int)fabs(a[i]-a[n/2]);
cout<<min<<endl;
算法2:采用分治策略求中位数
int n; //油井的数量
int x; //x坐标,读取后丢弃
int a[1000]; //y坐标
cin>>n;
for (int i=0; i<n; i++)
cin>>x>>a[i];
int y = select(0, n-1, n/2); //采用分治算法计算中位数。快速排序中的分割算法
//计算各油井到主管道之间的输油管道最小长度总和
int min=0;
for(int i=0;i<n;i++)
min += (int)fabs(a[i]-y);
cout<<min<<endl;

相关文章:

  • 2021-07-26
  • 2021-06-14
  • 2021-12-21
  • 2021-08-19
  • 2021-12-02
  • 2021-07-28
  • 2021-12-28
  • 2021-10-03
猜你喜欢
  • 2021-12-29
  • 2021-04-04
  • 2022-12-23
  • 2022-01-15
  • 2022-12-23
  • 2021-06-20
  • 2021-08-06
相关资源
相似解决方案