编程竞赛常用算法(基础)

简单介绍几个常用算法

1.快速幂

C/C++中#include<math.h>可以调用pow()函数

语法:

  #include <math.h>
  double pow( double base, double exp );

功能: 函数返回以参数base 为底的exp 次幂。如果base为零或负和exp 小于等于零或非整数时,产生域错误。如果溢出,产生范围错误。

======以上来自c/c++  API======


然而实际应用中存在可能需要自己编写这个函数,在过程中进行其他操作,例如洛谷 P1226 取余运算||快速幂

函数体也很简单:

int pow(int base, int exp){
	int ans=1;
	while(exp){
	    if(exp&1)
	        ans*=base;
	    base*=base;
	    exp>>=1;
	}
	return ans;
}

给一道稍微有点难度(难度在对矩阵乘法的理解)的练习题:hihoCoder-1143 骨牌覆盖问题·一

======快速幂结束======

2.搜索

搜索是一种常用的解题思路,最简单的两种搜索方式就是DFS与BFS

DFS(深度优先搜索)

DFS最经典的运用就是走迷宫,遍历所有可能,利用回溯来找到题解。一般的全排列题目可以考虑使用DFS。

N皇后问题就是一个标准的DFS算法。

贴一个全排列类的可以用DFS解决的蓝桥杯试题用于练习。2013蓝桥杯C高职T9-带分数


BFS(宽度优先搜索,又叫广度优先搜索)

最开始接触BFS是再算法导论中,书中用染色来表达搜索的过程。我的理解是:搜索前所有顶点都为白色,然后开始搜索,从起点开始将距离自己最近的(距离为1)的点全部标记为灰色(非白色),再从被标记为灰色的顶点继续搜索,这个顶点搜索完毕后,将这个顶点标记为黑色,再将所有距离这个点最近的点标记成灰色。以上就是BFS的基本思路。一般我会构造一个队列来保存灰色顶点。BFS的特性可以保证你所搜索到的解是最优解,即最短路径。

下面选取BFS较为简单的一道入门题:POJ3984 迷宫问题

定义一个二维数组: 
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
Input
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
Output
左上角到右下角的最短路径,格式如样例所示。

此题标题虽然是迷宫,但是分析题意,是找最短路线,寻找最短路径可以使用BFS进行搜索,一般进行BFS构造一个结构体包含x, y,并放在一个队列中,本题要求输出最优解的解集,因此用value保存染色的顺序,用father保存这个点是由从哪个点发现的。


#include<iostream>
using namespace std;
int map[5][5];
struct point{
	int x, y, value, father;
};
void display(){
	for(int i=0;i<5;i++){
		for(int j=0;j<5;j++){
			cout<<map[i][j]<<" ";
		}
		cout<<endl;
	}
}
bool check(int x, int y){
	return x>=0&&x<=4&&y>=0&&y<=4&&!map[x][y];
}
int main(){
	for(int i=0;i<5;i++){
		for(int j=0;j<5;j++){
			cin>>map[i][j];
		}
	}
	//display();
	int head=0, tail=0;
	point q[10000];
	q[head].x = 0;
	q[head].y = 0;
	q[head].value = 1;
	q[head].father = -1;
	map[0][0] = 1;
	int dic[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; 
	int x, y;
	bool flag = true;
	while(flag){
		//向四个方向搜索
		for(int i=0;i<4;i++){
			x = q[head].x + dic[i][0];
			y = q[head].y + dic[i][1];
			if(check(x, y)){
				tail++;
				q[tail].x = x;
				q[tail].y = y;
				q[tail].value = q[head].value + 1;
				q[tail].father = head;
				if(x==4&&y==4){
					flag = false;
					break;
				}else{
					map[x][y] = q[tail].value;
				}
			}
		}
		head++;
	}
	int i=0, ans[100];
	while(q[tail].father!=-1){
		tail = q[tail].father;
		ans[i] = tail;
		i++;
		
		
	}
	for(int j=i-1;j>=0;j--){
		cout<<"("<<q[ans[j]].x<<", "<<q[ans[j]].y<<")"<<endl;
	}
	cout<<"(4, 4)";
	return 0;
}

给一道蓝桥杯15年决赛题,蓝桥杯题库已经三年没有更新,此处贴上题目叙述

标题:穿越雷区

X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?
已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
坦克车只能水平或垂直方向上移动到相邻的区。

数据格式要求:
输入第一行是一个整数n,表示方阵的大小, 4<=n<100
接下来是n行,每行有n个数据,可能是A,B,+,-中的某一个,中间用空格分开。
A,B都只出现一次。

要求输出一个整数,表示坦克从A区到B区的最少移动步数。
如果没有方案,则输出-1

例如:
用户输入:
5
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -

则程序应该输出:
10

资源约定:
峰值内存消耗 < 512M
CPU消耗  < 1000ms

======搜索结束======

3.高精度

高精度四则运算原理是用计算机模拟小学竖式的计算方法完成超过了默认数据类型(如int,long long)的计算,一般用于计算超过2^63的数据(十位数以内用int,有符号int最大值2,147,483,647,20位以内用long long,有符号long long最大值9,223,372,036,854,775,807)

理解思想即可,一般遇不到需要高精度的题。

#include<iostream>
using namespace std;
#define N 200//根据数据规模调整 
string highPrecisionMul(const string a, const string b){
	string ans = "";
	for(int i=0;i<a.length()+b.length();i++)//初始化字符串 
		ans += '0';
	int temp;
	for(int i=0;i<a.length();i++){
		for(int j=0;j<b.length();j++){
			temp = (a[i]-'0')*(b[j]-'0')+(ans[i+j]-'0');
			ans[i+j] = temp%10+'0';
			ans[i+j+1] += temp/10;
		}
	}
	while(ans[ans.length()-1]=='0'){//删除(倒序时的)前导零 
		ans.erase(ans.length()-1);
	}
	return ans;
}
string highPrecisionAdd(const string a, const string b){
	string ans = "";
	int temp, len;
	len = a.length()>b.length()?a.length():b.length();
	for(int i=0;i<=len;i++)//初始化字符串
		ans += '0';
	for(int i=0;i<len;i++){
		temp = (a[i]-'0')+(b[i]-'0')+(ans[i]-'0');
		ans[i] = temp%10+'0';
		ans[i+1] = temp/10+'0';
	}
	while(ans[ans.length()-1]=='0'){//删除(倒序时的)前导零 
		ans.erase(ans.length()-1);
	}
	return ans;
}
void reverse(string &a){//倒置函数 
	int t;
	for(int i=0;i<a.length()/2;i++){
		t = a[i];
		a[i] = a[a.length()-i-1];
		a[a.length()-i-1] = t;
	}
}
int main(){
	cout<<"输入两个整数"<<endl; 
	string a, b;
	cin>>a>>b;
	reverse(a);
	reverse(b);
	string add = highPrecisionAdd(a, b);
	string mul = highPrecisionMul(a, b);
	reverse(add);
	reverse(mul);
	reverse(a);
	reverse(b);
	cout<<a<<"+"<<b<<"="<<add<<endl;
	cout<<a<<"*"<<b<<"="<<mul;
	return 0;
} 


给一道简单的高精度题目洛谷P1601 A+B Problem(高精)

其他基础算法再补充

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值