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;
}