蓝桥算法大总结:
一般解决问题最简单的算法:除简单逻辑处理之外,还有暴力、枚举是最重要的
暴力、枚举(一般是多重循环、注意边界、添加标志位可以加快解题)
while(scanf("%d",&n)!=EOF)
{
for( i = 0 ; i < n ; i++)
scanf("%d",&len[i]);
ans = -1;
for( i = 0 ;i < n;i++)
for( j = i+1 ; j < n ; j++)
for( k = j+1; k < n; k++)
{
if(len[i]*len[i]+len[j]*len[j]==len[k]*len[k]) //枚举出有直角三角形成立
if(0.5*len[i]+len[j]>ans)
ans = 0.5*len[i]*len[j];
}
}
怎么说呢,就是无限的for它就对了,然后注意边界值和出口
(for必达)
其实枚举也有好坏,数据不大的情况下就无脑枚举,如果算法超时了。。。但又没有更好的算法
可以尝试优化你的枚举
形如:
int x,y,z;
for(x = 1 ; x<=20;x++)
for(y = 1 ; y <=33 ; y++)
for(z = 1;z <= 100;z++)
if(x+y+z == 100 && 5*x+3*y+z/3 == 100 )
{
printf("公鸡数量=%d\t",x);
printf("母鸡数量=%d\t",y);
printf("雏鸡数量=%d\n",z);
}
//优化算法,不用再判断Z,已知x,y就可以求到z,且此时可以减少if中的判断
/*
int x,y,z;
for(x = 1 ; x<=20;x++)
for(y = 1 ; y <=33 ; y++)
{
z = 100 - x - y;
if(5*x+y*3+z/3==100)
{
printf("公鸡数量=%d\t",x);
printf("母鸡数量=%d\t",y);
printf("雏鸡数量=%d\n",z);
}
}
*/
那么就可以总结出枚举的优化其实就是逻辑减少你的无脑for循环
其他算法:
递归:
找出口(什么时候return出口) 总结规律,调用形如f(规律)的函数。
例子1:
hannoi(int n,char a,char b,char c)`
{
//所谓出口:n==1是出口
//所谓总结规律:
/*
其他分别是a上的n-1物品借助c挪动到b`
最后一个n直接从a到c
B上的n-1个物品借助a挪动到c
*/
//真实代码为
if(n==1) //定义出口
{
move(n,a,c); //只有一个时,直接将a上的东西挪动到c
}
else
{
hannoi(n-1,a,c,b);//如果a上不止一个东西,就借助c把前n-1个挪动到b
move(n,a,c);//然后将最后一个,(此时a上只有一个,c上没有,b上有n-1个)即第n个直接挪动到c
hannoi(n-1,b,a,c);//此时再把n-1个借助a从b挪到c(递归的思想在这里!!)
}
}
void move(int n,char x,char y)
{
printf("move %d from %c to %c\n",n,x,y);
num++;
}
其他简单例子:
n的阶乘n!
大概是这个样子
int f(int n)
{
if(n==1||n==0) return 1;//所谓出口
return n*f(n-1);//所谓规律
}
其他经典但不很简单的例子
快排
int PartSort(int* pArray, int nLeft, int nRight) //取键值
{
int nKey = pArray[nLeft]; //取头
while (nLeft < nRight)
{
while (pArray[nRight] >= nKey && nRight > nLeft) //最后的元素和头元素比较,即右指针
{
nRight--; //不是,拉回
}
pArray[nLeft] = pArray[nRight];//出来
while (pArray[nLeft] < nKey && nLeft < nRight) //和头元素比较,即左指针
{
nLeft++;
}
pArray[nRight] = pArray[nLeft];
}
pArray[nLeft] = nKey;
return nLeft;//找到序列分段的点
}
void QuickSortRecursion(int* pArray, int nLeft, int nRight)
{
if (NULL == pArray)
{
return;
}
if (nLeft >= nRight) //两边重合,退出
{
return;
}
int nMid = PartSort(pArray, nLeft, nRight); //拿到键值
//int nMid = pArray[(nLeft+nRight)/2]; 错误取法
QuickSortRecursion(pArray, nLeft, nMid - 1);//键值左边的快排
QuickSortRecursion(pArray, nMid + 1, nRight);//键值右边的快排
}
其中,快排最经典的还包括取指针的交换
void myswap(int *a,int *b)
{
int t;
t=*a;
*a=*b;
*b=t;
}
背包算法(dp):
dp算法分为多种,一般是01背包和完全背包,还有其他的变化背包问题
主要理解了01背包其他的…也还是不好理解(其实我只会01问题)
/*
* dp算法最主要的是要确定dp以一位数组还是以二维数组的形式
* dp[i]代表...其实我还不会...这个属于变化背包问题,视情况而定
* dp[i][j]一般代表总共要i个物品,一共有j总时间,能拿到的最大值
*/
/*
* 一般的01背包问题最主要的是初始化边界的问题
* 如:要0个物品,j的时间,那么最终的d[0][j]肯定都是0
* 再如:要i个物品,可是不给时间,那么最终的d[i][0]肯定都是0
* 就像这个鸭子去初始化就好啦 m代表物品个数,t代表时间
for(int i = 0 ; i <= m; i++)
dp[i][0] = 0;
for(int i = 0 ; i <= t; i++)
dp[0][i] = 0;
*/
//剩下的最主要的问题:就是怎么取的问题
直接上代码:
for(int i = 1; i <= m ; i++) //双重循环遍历整个背包
{
for(int j = 1; j <= t;j++)
{
if(j<time[i]) //不够时间取当下的物品,只能取前一个
{
dp[i][j] = dp[i-1][j];
printf("dp[%d][%d]=%d\n",i,j,dp[i-1][j]);//打印出来看看...
}
else
{
//时间足够,那么就比较前面已经取得的总价值和接下来要取的总价值的大小,取最大
dp[i][j] = max(dp[i-1][j],dp[i-1][j-time[i]]+price[i]);
printf("dp[i-1][j-time[i]]=dp[%d][%d]=%d\t",i-1,j-time[i],dp[i-1][j-time[i]]+price[i]);
printf("dp[%d][%d]=%d\n",i,j,dp[i][j]);
}
}
}
printf("%d",dp[m][t]);
其他的背包问题后续…等俺学会了再回来
迪杰斯特拉(Dijkstra)算法
对于图的算法,一般有Dijkstra算法和Floyd算法。会一个一般就可以了
其实我也只会dijkstra…够用了够用了,灵魂狗头
如果我写的太菜,这个博主写的dijkstra非常的详细
直接上代码
/* 局部代码如下 */
int dijsktra()
{
memset(dist,0x3f,sizeof dist); //这里的0x3f可以当成无穷大使用
dist[1] = 0;
for(int i = 0 ; i < n ; i++)
{
int t = -1; //便于更新第一个的值
for(int j = 1 ; j <= n ; j++)
{
if(!vis[j]&&(t==-1||dist[t]>dist[j]))
t = j;//没进过的点,或者第一个点,或者此时的t>j
}
vis[t] = 1;
for(int j = 1 ; i <= n ; j++)
{
//用t来更新其他点到起点的值
//比较此点和下一结点那个大,取最小
dist[j] = min(dist[j],dist[t]+g[t][j]);
}
}
if(dist[n]== 0x3f3f3f3f) return -1;
else return dist[n];
}
供你测试的代码如下:(如果你看得懂我怎么测试的话)
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
int g[N][N];
int dist[N];
bool vis[N];
int n,m;
int dijsktra()
{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
for(int i = 0 ; i < n ; i ++ )
{
int t = -1 ;
for(int j = 1 ; j <= n ; j++)
{
if(!vis[j]&&(t==-1||dist[t]>dist[j]))
t = j;
}
vis[t] = 1;
for(int j = 1 ; j <= n ; j++)
{
dist[j] = min(dist[j],dist[t]+g[t][j]);
}
}
if(dist[n] == 0x3f3f3f3f) return -1;
else return dist[n];
}
int main()
{
cin>>n>>m;
memset(g,0x3f,sizeof g);
for(int i = 0 ; i < m ; i++)
{
int x,y,z;
cin>>x>>y>>z;
g[x][y] = min(g[x][y],z);
}
cout<<dijsktra()<<endl;
return 0;
}
总结:其实最短路的问题,一般可以用脑神经回路算法解决,即肉眼观察法
那么,。如果你数据量实在不适合脑神经算法或者其他情况呢,或者你该用上dijsktra
这或许不是算法…
在c++中,如果你学会使用API函数后,就是那些STL函数啦,。那么你就会事倍功半事半功倍啦。
最常用的(就是我目前知道的)
如sort函数
sort(a,a+num)
//其中,a是你要传入的数组首地址,num是你这个数组有多少个数据
//你问我有多少个数据有时候不确定怎么办?凉拌???其实。。。。你可以用很多简单的算法或者小技巧就可以得到啦
//实在不行,拿手指头数它!
//那么解释一下,这个num的用处其实是确定你数据量的大小,会自动的选择时间复杂度更小的排序算法。如希尔、快排等
如memset函数
memset(dist,0x3f,sizeof dist);
/* 算法功能,初始化数组值 */
/* 其中,dist就是你要传入的数组,中间的是你要初始化的值 ,最后是你的数组大小*/
如一些查找算法binary_search();
binary_search(a,a+12,5);
/*
* 其中,a是数组,+12是数组长度,最后的5是你要找的数字 */
* 返回类型:bool型,0为没找到,1为找到
*/
API之lower_bound();函数
lower_bound(a,a+12,10)-a;
/*
* 作用:返回找到的第一个大于等于index_num的下标
* 参数:arr[]数组首地址,arr+数组长度,index_num查找的值
* 你问我为什么要减a?我也不知道.....其实呢,就是减去首地址,返回的才是下标值,就是这么用的,不必纠结
*/
顺便加上另一个差不多的
upper_bound(a,a+12,99)-a;
/**
* API之upper_bound();函数
* 作用:返回找到的第一个大于index_num的下标
* 参数:arr[]数组首地址,arr+数组长度,index_num查找的值
*/
c_srt()函数
/**
* API之c_str();函数
* 作用:返回一个char* 的指针
* 参数:直接.调用的形式
* 注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针
*/
char *cstr;
string str("Please hello to me");
cstr = new char [str.size()+1];
//strcpy(cstr,str.c_str());
cout<<str.c_str()<<endl;
return 0;
其实还有好些其他的常用函数
你问我还有哪些?
我好像暂时只记得这些。。。。 其实肯定有很多其他的
/----------------------------------------分割线-------------------------------------------------/
等待后续更新…