简单算法的编程实现

0.前言

最近看到了一些算法的有趣实现,因此记录一下,方便日后复习查看。

1.二分法求函数零点:

例如已知函数 l n ( x ) + x 2 ln(x)+x^2 ln(x)+x2在区间 [ 0 , 1 ] [0,1] [0,1]上单调,且有一个根,用数值法求解此根,精度0.0001。

思路:此题直接将区间告诉了,那么可以考虑用二分法求解,左区间就是0,右区间是1,每次求出左右区间的中间值代入函数与左区间的函数值比较,如果异号说明零点应该在左区间和中间值这段区间,如果同号说明零点应该在中间值和右区间这段区间内,否则就是找到零点,或者当左右区间相差较小时也认为找到了零点。代码如下:

#include<iostream>
#include<cmath>

//函数方程
double f(double x) {
	return log(x) + x * x;
}

double solve(double a, double b) {
	double eps = 1e-5;
	while (abs(a - b) > 2 * eps) {
		double mid = a + (b - a) / 2;
		if (f(a) * f(mid) < 0) {//说明零点在左区间到中间值范围内
			b = mid;
		}
		else if (f(a) * f(mid) == 0) {
			break;
		}
		else {//说明零点在中间值到右区间范围内
			a = mid;
		}
	}
	return (a + b) * 0.5;
}

int main() {
	std::cout << solve(0, 1) << std::endl;
	return 0;
}

2.蒙特卡罗方法模拟圆周率

代码如下:

#include <iostream>
#include <ctime>

using namespace std;

//使用蒙特卡洛法模拟求圆周率

double montecarlo_pi(int epochs) {
	double r = 1.0;//单位圆半径
	int count = 0;//生成的随机点落在单位圆内的数量
	double x = 0.0;
	double y = 0.0;
	srand((unsigned)time(NULL));
	for (int i = 0; i < epochs; i++) {
		//epochs模拟的次数即生成的点数
		x = rand() / (double)RAND_MAX;//生成(0,1)的随机小数
		y = rand() / (double)RAND_MAX;
		//cout << "x = " << x << " y = " << y << endl;
		if (sqrt(x * x + y * y) <= r) {
			//认为点在圆内
			count++;
		}
	}

	return 4.0 * count / epochs;
}

int main()
{
	int epochs = 1e7;
	double res = montecarlo_pi(epochs);
	cout << res << endl;
}

3.迷宫问题

给定一个由0和1组成的二维矩阵(0表示可以走,1表示不能走),从左上角位置出发,移动到矩阵右下角,每次移动只能向下或向右移动,输出一条起点到终点的路径。
这题我用的是DFS求解的,递归求解出所有起点到终点的路径,然后输出其中一条路径即可。这样也如果求最短路径或者最长路径的话也就顺便求出来了。代码如下:

#include <iostream>
#include <vector>
using namespace std;
// 0 0 1 0
// 0 0 0 0
// 0 1 1 0

vector<vector<vector<int>>> res;
vector<vector<int>> path;

void dfs(vector<vector<int>>& graph, int row, int col) {
	int n = graph.size();
	int m = graph[0].size();
	if (row == n - 1 && col == m - 1) {
		path.push_back({ row, col });
		res.push_back(path);
		path.pop_back();
		return;
	}
	path.push_back({ row, col });
	int len = path.size();
	if (row < 0 || row >= n || col < 0 || col >= m || graph[row][col] == 1) {
		if (!path.empty()) path.pop_back();
		return;
	}

	dfs(graph, row + 1, col);
	dfs(graph, row, col + 1);
	path.pop_back();
}

int main()
{
	int n = 3;
	int m = 4;
	vector<vector<int>> graph(n, vector<int>(m, 0));
	graph[0][2] = 1;
	graph[2][1] = 1;
	graph[2][2] = 1;

	dfs(graph, 0, 0);
	for (auto paths : res) {
		for (auto point : paths) {
			cout << point[0] << ' ' << point[1] << "->";
		}
		cout << endl;
	}
	

	return 0;
}


4.所有路径和

给定一个图中各边的连接关系,以及起点和终点,输出起点到终点的所有路径和,并从小到大排序。
还是主要考虑的DFS来实现找出所有路径,但因为要对路径大小进行排序,所以将结果保存在map中,这样运行完程序,顺序也排好了。代码如下:

#include <iostream>
#include <vector>
#include <map>

using namespace std;

class Node {
public:
	int id;//节点编号
	vector<int> neighbor;//相邻节点
	vector<int> weight;//对于相邻节点的权重

	Node() {
		id = 0;
	}
	Node(int _id) {
		id = _id;
	}
};

map<int, vector<int>> res;//路径集合,第一个表示路径权重,第二个表示路径
vector<int> path;//一条路径
int sum = 0;//一条路径权重
void dfs(vector<Node>& graph, vector<int>& visit, int cur, int end) {
	if (cur == end) {
		//当前节点为终点
		path.push_back(end);
		res[sum] = path;
		path.pop_back();//弹出最后一个节点
		visit[cur] = 0;//清除标记
		return;
	}
	path.push_back(cur);//当前节点加入
	visit[cur] = 1;//已访问
	for (int i = 0; i < graph[cur].neighbor.size(); i++) {
		if (!visit[graph[cur].neighbor[i]]) {//相邻节点没有访问过
			sum += graph[cur].weight[i];//当前节点到相邻节点的权重
			dfs(graph, visit, graph[cur].neighbor[i], end);//递归相邻节点
			sum -= graph[cur].weight[i];
		}
	}
	path.pop_back();
	visit[cur] = 0;
}

int main()
{
	//int n = 6;//节点数量
	//vector<Node> graph(n + 1);//带权有向图
	构建边
	//graph[1].neighbor.push_back(2);//1->2
	//graph[1].weight.push_back(3);//权重3
	//graph[1].neighbor.push_back(3);//1->3
	//graph[1].weight.push_back(2);//权重2
	//graph[1].neighbor.push_back(4);//1->4
	//graph[1].weight.push_back(1);//权重1
	//graph[2].neighbor.push_back(5);//2->5
	//graph[2].weight.push_back(2);//权重2
	//graph[3].neighbor.push_back(6);//3->6
	//graph[3].weight.push_back(1);//权重1
	//graph[4].neighbor.push_back(6);//4->6
	//graph[4].weight.push_back(4);//权重4
	//graph[4].neighbor.push_back(5);//4->5
	//graph[4].weight.push_back(3);//权重3
	//graph[6].neighbor.push_back(5);//6->5
	//graph[6].weight.push_back(3);//权重3
	起点和终点
	//int start = 1;
	//int end = 5;

	int n, m;//节点数量、边数量
	cin >> n >> m;
	vector<Node> graph(n + 1);//带权有向图
	for (int i = 0; i < m; i++) {
		int s, e, w;
		cin >> s >> e >> w;//起点、终点、权重
		graph[s].neighbor.push_back(e);
		graph[s].weight.push_back(w);
	}
	int start, end;//起点、终点
	cin >> start >> end;

	vector<int> visit(n + 1, 0);//节点是否访问过,0未访问,1访问
	dfs(graph, visit, start, end);

	for (auto ans : res) {
		cout << ans.first << ": ";
		for (int p = 0; p < ans.second.size(); p++) {
			if (p != ans.second.size() - 1) cout << ans.second[p] << "->";
			else cout << ans.second[p];
		}
		cout << endl;
	}
	return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值