首先,对直到现在为止的学习做一个 总的总结:
1.基本的编程语言运用。。。。(不再废话,如有需要请访问另一篇总结博客)
2.递推算法:递推算法是一种用若干步可重复运算来描述复杂问题的方法(概念),至于具体的。。比如说求斐波那契数列:
for(int i=1;i<=n;++i){
a[i+2]=a[i]+a[i+1];
}//不错就是这么短
3.递归算法:在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法(不错又是概念),好的不要管他,用通俗的说法就是自己调用自己(很通俗吗??),比如说,随便举一个代码的例子,求一串数的和,当前i个数的和大于100时,输出他们的和。
int p=1;
int dfs(int num){
if(num>100)return num;
else dfs(num+a[p++]);
}
4.贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择(其实我只是懒得写概念),比如说两个教练选球员,每个球员有自己的技巧值,教练会先选技巧值高的然后选技巧值低的,具体看代码:
bool resort(int x,int y){
return x>y;
}
.......(省略细节)
sort(a+1,a+n+1,resort);//这个是指将a数组的1到n项(即a[1]~a[n])从大到小排序;
int p=1;
for(int i=1;i<=n;++i){
if(i%2==1)jiaoshou1+=a[p++];
else jiaoshou2+=a[p++];
}
.......(继续省略细节)
5.深搜(大名:深度优先搜索)深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点 。(以上是概念)说简单了,也相当于递归,概念大概就是:你到一条有分叉路口的街上去买东西,首先你选择一条路走到底,当没有发现要买的物品时,回到上一个岔路口,选择另一条路再走到底。(以下代码是一道深搜题,大致题意:奶牛们在一个5*5的格子里跳,每个格子里有数字,奶牛可以从任何一个格子开始跳,当跳满6个格子时,按他跳的顺序组成一个六位数,问能组成几个不同的数字)
void jump(int e,int f,int g,int h){
if(e>5||e<1||f>5||f<1) return;//跳出格子了
if(g==6)跳满了6个
{
if(b[h]==0)
{
b[h]=1;
ans++;
}
return;
}
jump(e+1,f,g+1,h*10+a[e+1][f]);
jump(e-1,f,g+1,h*10+a[e-1][f]);
jump(e,f+1,g+1,h*10+a[e][f+1]);
jump(e,f-1,g+1,h*10+a[e][f-1]);//四个方向跳
}
6.广搜(广度优先搜索)广度优先算法(Breadth-First Search),同广度优先搜索,又称作宽度优先搜索,或横向优先搜索,简称BFS,是一种图形搜索演算法。简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,则演算终止。广度优先搜索的实现一般采用open-closed表。(好的又是概念)接下来我们坐电梯(题面:坐电梯,每层楼有一个有固定数值的按钮,只能上升或者下降按钮上的数字的层,求最少到达目标层的最少次数):
void bfs(int here,int y){
if(y>=minnest) return;//比先前到达目标层的次数多,一定不是最优
if(here==b){//到了目标层
minnest=min(minnest,y);
return;
}
if(here-k[here]>0&&look[here-k[here]]==false)//下降,并且下降后到达的楼层未到达过
{
look[here-k[here]]=true;
bfs(here-k[here],y+1);
look[here-k[here]]=false;
}
if(here+k[here]<=n&&look[here+k[here]]==false)//上升,并且上升后到达的楼层未到达过
{
look[here-k[here]]=true;
bfs(here+k[here],y+1);
look[here-k[here]]=false;
}
}
7.动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。(好的以上又是概念)DP有很多分类,比如线性DP,区间DP,树形DP,背包问题,以下会分类。
7.1.背包问题:For example,经典例题“采药”(01背包):山洞里有n棵药,采每棵药需要t[i]的时间,每棵药有v[i]的价值,求在一定时间内能够得到的最大价值。
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
a[i][j]=a[i-1][j];
if(j-s[i]>=0){
if(a[i-1][j-s[i]]+w[i]>a[i][j]){
a[i][j]=a[i-1][j-s[i]]+w[i];//状态转移方程
}
}
}
}
7.2.线性DP:合唱队形:N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形,合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...Ti+1>…>TK(1<=i<=K)。代码如下:
for(int i=1;i<=n;++j){
for(int j=1;j<i;++j){
if(a[i]>a[j]){
b[i]=max(b[i],b[j]);
b[i]++;
}
}
}
for(int i=n;i>=1;--i)
{
for(int j=n;j>=i+1;--j){
if(a[i]>a[j]){
c[i]=max(c[j],c[i]);
c[i]++;
}
}
}
for(int i=1;i<=n;++i)ans=max(ans,b[i]+c[i]-1);
cout<<n-ans<<endl;
7.3。树形DP:例如数字三角形(题目有点难描述,给出洛谷网址https://www.luogu.org/problemnew/show/P1216)好的以下看标程:
for(int i=r-1;i>=1;--i){
for(int j=i;j>=1;--j){
if(a[i+1][j+1]>=a[i+1][j])a[i][j]+=a[i+1][j+1];
else a[i][j]+=a[i+1][j];
}
}//注意,这里是从下往上的
7.4.区间DP:石子合并:在操场上沿一直线排列着n堆石子。将石子有次序地合并成一堆。每次只能选相邻的两堆石子合并成新的一堆,并将新的一堆石子数计为该次合并的得分,并且让n-1次合并后得到的得分总和最小。
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]+b[i-1];
c[i][i]=0;
d[i][i]=i;
}
for(int i=1;i<n;i++){
for(int j=1;j+i<=n;j++){
c[j][i+j]=10000000;
for(int k=d[j][i+j-1];k<=d[j+1][i+j];k++){
if(c[j][i+j]>c[j][k]+c[k+1][i+j]){
c[j][i+j]=c[j][k]+c[k+1][i+j];
d[j][i+j]=k;
}
}
c[j][i+j]+=b[i+j]-b[j-1];
}
}
8.图论:(概念)图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。以下给出求最短路(求A到B的最短路径)和最小生成树(将图上所有点联通的最小代价)的几种算法。
8.1.最短路:电车:在一个神奇的小镇上有着一个特别的电车网络,它由一些路口和轨道组成,每个路口都连接着若干个轨道,每个轨道都通向一个路口(不排除有的观光轨道转一圈后返回路口的可能)。在每个路口,都有一个开关决定着出去的轨道,每个开关都有一个默认的状态,每辆电车行驶到路口之后,只能从开关所指向的轨道出去,如果电车司机想走另一个轨道,他就必须下车切换开关的状态。为了行驶向目标地点,电车司机不得不经常下车来切换开关,于是,他们想请你写一个程序,计算一辆从路口A到路口B最少需要下车切换几次开关。以下是代码(伪)
for(int j=1;j<=x;j++){
cin>>b;
if(j==1)a[i][b]=0;
else a[i][b]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
for(int o=1;o<=n;o++){
a[j][o]=min(a[j][o],a[j][i]+a[i][o]);
}
}
}//Dijkstra算法
8.2.最小生成树:约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。伪代码如下
struct line{
int l,r,w;
}a[1000000];
bool eee(line x11,line y11){
return x11.w<y11.w;
}
int n,aa,b[1000000]={},c=1,d,ans=0;
int zbb(int p){
if(b[p]==p) return p;
return zbb(b[p]);
}
.......(省略细节)
for(int i=1;i<=n;i++)
{
b[i]=i;
for(int j=1;j<=n;j++){
cin>>aa;
if(aa!=0){
a[c].l=i;
a[c].r=j;
a[c].w=aa;
c++;
}
}
}
sort(a+1,a+c,eee);//将权值从小到大排序
for(int i=1;i<c;i++){
if(zbb(a[i].l)!=zbb(a[i].r)){
ans+=a[i].w;
b[zbb(a[i].l)]=a[i].r;
d++;
if(d==n)break;
}
}//Kruskal算法
.......(省略细节)