当前位置:文档之家› C++基础复习

C++基础复习

C++算法基础复习NOIP20141.二分法通过每次把答案所在小区间收缩一半的方法,使区间的两个端点逐步迫近答案,以求得答案(近似值),这种方法叫做二分法。

一般来说,能够应用二分法的题目必须满足以下条件:答案存在单调性,通常用于对于二分所得到的答案进行验证,或者对数组进行查找。

时间复杂度:O(n*log n)①对一个数组进行查找,要求返回查找元素在数组中的位置,若不存在,则返回-1(查找数据)int search(int* a, int len, int goal){int low = 0;int high = len - 1;while(low <= high) //边界条件{int middle = (low + high)/2; //定义中间数据if(a[middle] == goal) return middle; //若找到答案,返回答案位置else if(a[middle] > goal) high = middle - 1; //大于答案,向右查找else low = middle + 1; //小于答案,向左查找}return -1; //未找到答案,返回-1}②对答案的二分查找double find(){double l,r,mid;const double e=0.0001; //浮点数精度设置while(r-l>e){mid=(l+r)/2;if(f(mid)) l=mid; //f(x)为条件函数,用来验证答案是否符合要求else r=mid;}return r;}2.动态规划把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

动态规划适用于与前文有关,并且与后面的数据无关的题目。

动态规划可以求解多种类型的问题,比如上升序列,下降序列,最大连续子串等。

由于动态规划算法的多样性,时间复杂度各有千秋。

①线性查找:上升序列,下降序列,最大连续子串等。

时间复杂度O(n2)/O(n) :(1)导弹拦截:for(int i=0;i<n;i++){Max=0; //最长上升序列Maxdown=0; //最长下降序列for(int j=0;j<i;j++){if(b[j]>Max&&a[j]>=a[i]) Max=b[j]; //能够连接的,并且最长的序列if(c[j]>Maxdown&&a[j]<a[i]) Maxdown=c[j];}b[i]=Max+1;c[i]=Maxdown+1;if(b[i]>Maxi) Maxi=b[i]; //对这个数据进行赋值if(c[i]>maxi) maxi=c[i];}注意,最长上升序列等于下降序列的个数,最长下降序列等于上升序列的个数。

(2)最大字段和:for(int i=1;i<=n;i++){if(b[i-1]>=0) b[i]=b[i-1]+a[i]; //如果上一个大于0,继续;else b[i]=a[i]; //否则重新开始Max=max(b[i],Max); //寻找最大值}②动规的图查找:有方向性的图。

时间复杂度O(n2)/O(n) :(1)在一个n*n的棋盘上的P点有一个中国象棋的马,而另一个点Q为马的家。

同时约定,Q在P的右边,马只能走日字,并只能向右走.for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) //每个点的xy坐标依次搜索{for(int s=0;s<4;s++){ //向各个方向查找nx=j+xx[s],ny=i+yy[s]; //当前坐标if(没有越界) dp[j][i]+=dp[nx][ny]; } //更新dp的数值}(2)给定一个N层的数字金子塔,从顶至底有多条路径,每一步可沿左斜线向下或沿右斜线向下。

路径所经过的数字之和为路径得分,请求出最大路径得分。

for(int i=0;i<n;i++) for(int j=0;j<=i;j++){if(i==0) b[i][j]=a[i][j];else if(j==0) b[i][j]=b[i-1][j]+a[i][j];else if(j==i) b[i][j]=b[i-1][j-1]+a[i][j]; //边界判断else b[i][j]=max(b[i-1][j],b[i-1][j-1])+a[i][j]; //找出上一层的最大值}③动规的区间查找:(枚举区间宽度,区间起点等)(1)石子合并:for(int i=0;i<n;i++) // 枚举区间宽度{for(int J=0;J<2*n-i-1;J++) //枚举起点{Max=0,Min=0;查询2起点,宽度为249起点,宽度为24 if(i!=0) Min=9999999;for(int x=J;x<J+i;x++) //找到这个区间内,使得合并代价最大/最小的切分点{Max=max(Max,B[J][x]+B[x+1][J+i]+sum[J][J+i]);Min=min(Min,C[J][x]+C[x+1][J+i]+sum[J][J+i]);}B[J][J+i]=Max;C[J][J+i]=Min; //赋值}}(2)RMQ :用DP 求区间的最大值和最小值。

O(nlogn)for(int j=1;j<=int(log(n)/log(2));j++) //前期数据处理,枚举宽度(2的倍数)for(int i=1;i<=n+1-(1<<j);i++) //枚举起点{Fmax[i][j]=max(Fmax[i][j-1],Fmax[i+(1<<(j-1))][j-1]);Fmin[i][j]=min(Fmin[i][j-1],Fmin[i+(1<<(j-1))][j-1]);}k=int(log(y-x+1)/log(2)); //查询部分,通过叠加查询Max=max(Fmax[x][k],Fmax[y+1-(1<<k)][k]);Min=min(Fmin[x][k],Fmin[y+1-(1<<k)][k]);(2)奶牛吃草:区间内最大和。

O(n)for(int i=1;i<=last;i++) {t1=t1-a[i-1]+a[i+2*m]; //减去离开窗口的数据,加入新进窗口的数据ans=max(ans,t1);}3. (优先)队列、栈的声明① 优先队列的声明(1)数据类型标准变量类型priority_queue<int> mypq; //默认int 从大到小建立优先队列priority_queue<int,vector<int>,greater<int> > mypq; //从小到大建立优先队列(2)数据类型为结构体类型struct data{int t,s;bool operator <(const data &rhs)const{return t<rhs.t;}};priority_queue<data> Q; #include<queue>② 队列的声明queue<int> list; #include<queue>③ 栈的声明stack<int> list; #include<stack>4. 搜索实际应用① 全排列类型void AllSort(int now){if(now==n){for(int i=0;i<n;i++) {cout<<a[i];if(i!=n-1)cout<<" ";} cout<<endl;num++;}for(int i=1;i<=n;i++){if(b[i]==false){a[now]=i;b[i]=true;AllSort(now+1);b[i]=false; //回溯部分}}}②染色类型inline void find(int nx,int ny){if(不符合染色条件||越界) return;map[nx][ny]=color; //开始染色for(int i=0;i<4;i++) find(nx+xx[i],ny+yy[i]); //递归染色}③01类型void dfs(int now,int setp){if(ok()) //判断结束条件{if(setp<=mins)mins=setp; //具体搜索的内容return;}if(now>=20) return;fanzhuan(now); //01翻转(也可以是选取不选取等一系列01问题)dfs(now+1,setp+1);fanzhuan(now); //回溯dfs(now+1,setp); //深搜}④联动类型问题(一个叫两个,两个叫剩下的几个)——宽搜:spfa的基础inline void bfs(){time2[1]=a[1].times;list.push(a[1]); //把起点push进去used[1]=1;while(list.size()){front=list.front();list.pop();for(int j=1;j<=front.num;j++){宽搜内容的修改语句(时间,步伐等)if(used[front.next[j]]==0){list.push(a[front.next[j]]);used[front.next[j]]=1; //把没访问过的点继续宽搜}}}}5.环类问题while(now!=i) //查找环{visit[now]=1;(如果是判定内部循环,还应该加一个if(visit[i]) break;)now=news[olds[now]];len++;if(visit[now]) break;}6.离散化问题①左右端点离散化:城市投影,干草包堆(1)城市投影void searchs(){for(int i=0;i<n*2;i++){if(x[i].LR==0) //左右端点{list.push(y[x[i].hg]);}else{out[x[i].hg]=1;}if(x[i].a!=x[i+1].a){while(list.size()>0&&out[list.top().num]==1) list.pop();if(list.size())num+=(long long)(x[i+1].a-x[i].a)*list.top().olds;}}}②数据范围缩小:sort一遍,重新按照大小编号123。

相关主题