1.枚举
枚举法,也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素。题目中给定的检验条件判定哪些是无用的,哪些是有用的。
优点是算法简单,在局部地方使用枚举法,效果十分好。缺点是运算量过大,当问题的规模变大的时候,循环的阶数越大,执行速度越慢。
例题:
百钱买白鸡问题:有一个人有一百块钱,打算买一百只鸡。到市场一看,公鸡一只3元,母鸡一只5元,小鸡3只1元,试求用100元买100只鸡,各为多少才合适?
解析:
根据题意可以得到方程组:3X+5Y+Z/3=100;X+Y+Z=100;
#include<iostream>
using namespace std;
int main()
{
int x,y,z;
for(x=0;x<=100;x++)
{
for(y=0;y<=100;y++)
{
for(z=0;z<=100;z++)
{
if(x+y+z==100&&3*x+5*y+z/3==100&&z%3==0)
cout<<x<<" "<<y<<" "<<z<<endl;
}
}
}
return 0;
}
优化:利用方程组3X+5Y+Z/3=100;X+Y+Z=100;可将Z约去,得到新方程组4X+7Y=100
#include<iostream>
using namespace std;
int main()
{
int x,y,z;
for(x=0;x<=25;x++)
{
y=100-4*x;
if(y%7==0&&y>=0)
{
y=y/7;
z=100-x-y;
if(z%3==0&&3*x+5*y+z/3==100)
cout<<x<<" "<<y<<" "<<z<<endl;
}
}
return 0;
}
2.递推
递推算法是一种简单的算法,即通过已知条件,利用特定关系得出中间推论,直至得出结果的算法。
例题:斐波那契数列
因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”。
fibonacci 数列定义:
n = 1,2 时,fib(n) = 1
n > 2 时,fib(n) = fib(n-2) + fib(n-1)
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,……….
解析:
递归算法
#include<iostream>
using namespace std;
int fib(int n)
{
if(n<=1)
return n;
else
return fib(n-1)+fib(n-2);
}
int main()
{
int n;
cin>>n;
cout<<fib(n);
return 0;
}
优化
#include<iostream>
using namespace std;
int fib(int n)
{
int a=0;int b=1;int c;
for(int i=2;i<=n;i++)
{
c=a+b;
a=b;
b=c;
}
return c;
}
int main()
{
int n;
cin>>n;
cout<<fib(n);
return 0;
}
3.贪心算法
所谓贪心算法是指在对问题求解时,总是作出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。
例题:合并果子
现在又n堆果子,第i堆有ai个果子。现在要把这些果子合并成一堆,每次合并的代价是两堆果子的总果子数。求合并所有果子的最小代价。
解析:每次选取最少的两堆合并,直到剩一堆即可。
#include<iostream>
#define maxsize 100
using namespace std;
void sort(int *a,int low,int high)
{
int i=low,j=high;
int temp=a[i];
if(low>high)
return;
while(i<j)
{
while(i<j&&a[j]>=temp)
j--;
if(i<j)
a[i]=a[j];
while(i<j&&a[i]<=temp)
i++;
if(i<j)
a[j]=a[i];
}
a[j]=temp;
sort(a,low,i-1);
sort(a,i+1,high);
}
void merge(int a[],int n)
{
sort(a,0,n-1);
int ans=0;
for(int i=1;i<n;i++)
{
a[i]+=a[i-1];
ans+=a[i];
int temp=a[i];
for(int j=i+1;j<n&&a[j]<a[i];j++)
{
a[j-1]=a[j];
a[j]=temp;
}
}
cout<<ans<<endl;
}
int main()
{
int a[maxsize];
int n,i;
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
merge(a,n);
return 0;
}
利用优先队列的方法优化
普通的队列是一种先进先出的数据结构,元素在队列尾追加,而在队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出的行为特征。通常采用堆数据结构来实现。
priority_queue
基本操作:
empty():如果队列为空,则返回真
pop():删除对顶元素,删除第一个元素
push():加入一个元素
size():返回优先队列中拥有的元素个数
top():返回优先队列对顶元素,返回优先队列中有最高优先级的元素
头文件:#include<queue>
声明方式:
1.普通方法
priority_queue<int> q;//通过操作,按照元素从大到小的顺序出队
priority_queue<int,vector<int>,greater<int>> q;//通过操作,按照元素从小到大的顺序出队
2、自定义优先级:
struct cmp {
operator bool ()(int x, int y)
{
return x > y; // x小的优先级高 //也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高
}
};
priority_queue<int, vector<int>, cmp> q; //定义方法
//其中,第二个参数为容器类型。第三个参数为比较函数。
3、结构体声明方式:
struct node {
int x, y;
friend bool operator < (node a, node b)
{
return a.x > b.x; //结构体中,x小的优先级高
}
};
priority_queue<node>q; //定义方法
//在该结构中,y为值, x为优先级。
//通过自定义operator<操作符来比较元素中的优先级。
//在重载”<”时,最好不要重载”>”,可能会发生编译错误
#include<iostream>
#include<queue>
using namespace std;
int main()
{
priority_queue<int,vector<int>,greater<int> >p;
int n,m;
int a,b,result=0;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
p.push(m);
}
while(p.size()>=2)
{
int a=p.top();p.pop();
int b=p.top();p.pop();
result+=a+b;
p.push(a+b);
}
cout<<result<<endl;
return 0;
}