文章目录
一、输入与计算
1.1 读取数据(循环读取)
1.1.1 通过getline函数可以获取一行输入数据,第三个参数表示输入的间隔符,默认为’\n’。可以将数据读入char数组,也可以读入std::string中。
#include <iostream>
#include <string>
int main()
{
std::string data;
std::getline(std::cin, data);
int count = 0;
for (int i = data.size() - 1; i >= 0; i--)
{
if (data[i] == ' ') break;
else count++;
}
std::cout << count << std::endl;
}
char data[1024];
std::cin.getline(data, 1024);
1.1.2 循环从终端读入一行一行的数据。以行为读取单位。
#include <iostream>
#include <string>
int main()
{
std::string data;
std::getline(std::cin, data);
char ch;
std::cin >> ch;
int count = 0;
for (int i = 0; i < data.size(); i++)
{
if (data[i] == std::toupper(ch) || data[i] == std::tolower(ch))
count++;
}
std::cout << count << std::endl;
}
1.1.3 循环获取终端的数据,处理后输出。
#include <iostream>
#include <string>
int main()
{
std::string data;
while (std::getline(std::cin, data))
{
int count = 8 - data.size() % 8;
for (int i = 0; i < data.size(); i++)
{
if (i % 8 == 0 && i != 0)
{
std::cout << std::endl;
}
std::cout << data[i];
}
if (count == 8) count = 0;
for (int i = 0; i < count; i++)
{
std::cout << "0";
}
std::cout << std::endl;
}
}
1.2 十六进制转换为十进制
#include <iostream>
#include <string>
#include <cmath>
int main()
{
std::string data;
while (std::getline(std::cin, data))
{
unsigned int count = data.size() - 3;
int value = 0;
for (int i = 2; i < data.size(); i++)
{
char num = data[i];
if (num >= '0' && num <= '9')
value += std::pow(16, count) * (num - '0');
else if (num >= 'A' && num <= 'F')
value += std::pow(16, count) * ((num - 'A') + 10);
else if (num >= 'a' && num <= 'f')
value += std::pow(16, count) * ((num - 'a') + 10);
count--;
}
data.clear();
std::cout << value << std::endl;
}
}
1.3 四舍五入并取整
#include <iostream>
#include <string>
int main()
{
float number = 0.0f;
std::cin >> number;
int value = number * 10;
std::string data = std::to_string(value);
if (data.back() >= '5')
std::cout << int(number + 0.5f) << std::endl;
else
std::cout << int(number) << std::endl;
return 0;
}
1.4 统计一个整数的二进制中1的个数
#include <iostream>
int main()
{
int number = 0;
std::cin >> number;
int count = 0;
while (number)
{
count++;
number &= (number - 1);
}
std::cout << count << std::endl;
}
1.5 统计IP的类别以及掩码是否正确
#include <iostream>
#include<string>
#include <vector>
bool regular(std::string& ip)
{
int index1 = ip.find_first_of('.');
std::string se1 = ip.substr(0, index1);
int index2 = ip.find_first_of('.', index1 + 1);
std::string se2 = ip.substr(index1 + 1, index2 - index1 - 1);
int index3 = ip.find_first_of('.', index2 + 1);
std::string se3 = ip.substr(index2 + 1, index3 - index2 - 1);
std::string se4 = ip.substr(index3 + 1);
std::vector<std::string> vec = { se1, se2, se3, se4 };
for (int i = 0; i < vec.size(); i++)
{
if (vec[i].empty()) return false;
int size = 3 - vec[i].size();
for (int j = 0; j < size; j++)
{
vec[i] = "0" + vec[i];
}
}
ip = vec[0] + '.' + vec[1] + '.' + vec[2] + '.' + vec[3];
return true;
}
bool seOk(std::string& se)
{
if (se == "255" || se == "000") return true;
//->将十进制数转换为二进制字符串
std::string value;
int num = std::atoi(se.c_str());
while (num)
{
if (num % 2 == 0) value = "0" + value;
else value = "1" + value;
num /= 2;
}
int index = value.find_first_of("0");
for (int i = 0; i < index; i++)
{
if (value[i] == '1') return false;
}
return true;
}
bool isIpMask(std::string& ip)
{
if (ip == "255.255.255.255" || ip == "000.000.000.000")
return false;
int index1 = ip.find_first_of('.');
std::string se1 = ip.substr(0, index1);
int index2 = ip.find_first_of('.', index1 + 1);
std::string se2 = ip.substr(index1 + 1, index2 - index1 - 1);
int index3 = ip.find_first_of('.', index2 + 1);
std::string se3 = ip.substr(index2 + 1, index3 - index2 - 1);
std::string se4 = ip.substr(index3 + 1);
if ( (se1 == "255" && se2 == "255" && se3 == "255" && se4 != "255")
|| (se1 == "255" && se2 == "255" && se3 != "255" && se4 == "000")
|| (se1 == "255" && se2 != "255" && se3 == "000" && se4 == "000")
|| (se1 != "255" && se2 == "000" && se3 == "000" && se4 == "000"))
{
bool value = true;
value = value && seOk(se1);
value = value && seOk(se2);
value = value && seOk(se3);
value = value && seOk(se4);
return value;
}
return false;
}
int main()
{
std::string data;
int A = 0, B = 0, C = 0, D = 0, E = 0, S = 0, O = 0;
while (std::getline(std::cin, data))
{
if (data.empty()) break;
std::string ip = data.substr(0, data.find_first_of('~'));
if (!regular(ip))
{
O++;
continue;
}
std::string mask = data.substr(data.find_first_of('~') + 1);
if (!regular(mask))
{
O++;
continue;
}
if (ip.substr(0, ip.find_first_of('.')) == "000"
|| ip.substr(0, ip.find_first_of('.')) == "127")
{
continue;
}
if (!isIpMask(mask))
{
O++;
continue;
}
if (ip >= "001.000.000.000" && ip <= "126.255.255.255")
{
A++;
}
else if (ip >= "128.000.000.000" && ip <= "191.255.255.255")
{
B++;
}
else if (ip >= "192.000.000.000" && ip <= "223.255.255.255")
{
C++;
}
else if (ip >= "224.000.000.000" && ip <= "239.255.255.255")
{
D++;
}
else if (ip >= "240.000.000.000" && ip <= "255.255.255.255")
{
E++;
}
if ( ip >= "010.000.000.000" && ip <= "010.255.255.255"
|| ip >= "172.016.000.000" && ip <= "172.031.255.255"
|| ip >= "192.168.000.000" && ip <= "192.168.255.255")
{
S++;
}
data.clear();
}
std::cout << A << " " << B << " " << C << " " << D << " " << E << " " << O << " " << S << std::endl;
}
1.6 数字转英文
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
std::string print(std::string& value, std::map<int, std::string>& map)
{
std::string data;
if (value[0] != '0' && (value[1] != '0' || value[2] != '0'))
{
data += map[value[0] - '0'] + " hundred and ";
}
else if (value[0] != '0')
{
data += map[value[0] - '0'] + " hundred ";
}
if (value[1] > '1' && value[2] == '0')
{
data += map[(value[1] - '0') * 10];
}
else if(value[1] == '1')
{
if(value[2] == '0')data += map[(value[1] - '0') * 10];
else data += map[(value[1] - '0') * 10 + (value[2] - '0')];
}
else if (value[1] != '0' && value[2] != '0')
{
data += map[(value[1] - '0') * 10] + " " + map[(value[2] - '0')];
}
else if (value[2] != '0')
{
data += map[value[2] - '0'];
}
return data;
}
int main()
{
std::map<int, std::string> map =
{
{1,"one"},{2,"two"},{3,"three"},{4,"four"},{5,"five"},{6,"six"},{7,"seven"},{8,"eight"},{9,"nine"},{10,"ten"},
{20,"twenty"},{30,"thirty"},{40,"fouty"},{50,"fifty"},{60,"sixty"},{70,"seventy"},{80,"eighty"},{90,"ninety"},
{11,"eleven"},{12,"twelve"},{13,"thirteen"},{14,"fourteen"},{15,"fifteen"},{16,"sixteen"},{17,"seventeen"},{18,"eighteen"},{19,"nineteen"}
};
std::string data;
std::cin >> data;
int count = 1;
std::reverse(data.begin(), data.end());
for (int i = 0; i < data.size(); i++)
{
if (count % 4 == 0)
{
data.insert(data.begin() + i, ',');
}
count++;
}
data += ",";
std::map<int, std::string> word = { {4,"billion"},{3,"million"},{2,"thousand"},{1,"hundred"} };
std::string::size_type index0 = 0;
std::string::size_type index1 = data.find_first_of(',');
int c = 1;
std::string result;
while (index1 != std::string::npos)
{
std::string value = data.substr(index0, index1 - index0);
std::reverse(value.begin(), value.end());
while (value.size() < 3) value = "0" + value;
std::string w = "";
if (c > 1) w = " " + word[c] + " ";
result = print(value, map) + w + result;
index0 = index1 + 1;
index1 = data.find_first_of(',', index0);
c++;
}
std::cout << result;
return 0;
}
1.7 超大数相加
#include <iostream>
#include <string>
int main()
{
std::string data1, data2;
std::cin >> data1 >> data2;
int min = std::min(data1.size(), data2.size());
int max = std::max(data1.size(), data2.size());
std::string data;
data.resize(max + 1, '0');
for (int i = data1.size() - 1, j = data2.size() - 1, index = 0; i >= 0 && j >= 0; i--, j--, index++)
{
int value = (data[index] - '0') + (data1[i] - '0') + (data2[j] - '0');
int m = value / 10;
int n = value % 10;
data[index] = std::to_string(n).back();
data[index + 1] = std::to_string(m).back();
}
for (int i = min; i < max; i++)
{
if (i < data1.size())
{
int value = (data[i] - '0') + (data1[data1.size() - 1 - i] - '0') ;
int m = value / 10;
int n = value % 10;
data[i] = std::to_string(n).back();
data[i + 1] = std::to_string(m).back();
}
else if(i < data2.size())
{
int value = (data[i] - '0') + (data2[data2.size() - 1 - i] - '0');
int m = value / 10;
int n = value % 10;
data[i] = std::to_string(n).back();
data[i + 1] = std::to_string(m).back();
}
}
int index = data.size() - 1;
if (data.back() == '0')
{
index = data.size() - 2;
}
for (int i = index; i >= 0; i--)
{
std::cout << data[i];
}
return 0;
}
二、复杂度优化
2.1 计算质数因子
2.1.1 一般方法
#include <iostream>
int main()
{
int number;
std::cin >> number;
for (int i = 2; i <= number; i++)
{
while (number % i == 0)
{
std::cout << i << " ";
number /= i;
}
}
return 0;
}
2.1.2 采用上述计算方式,运行时间超出要求,需要进行优化,优化后的算法如下,主要在于减少循环次数。
#include <iostream>
#include <cmath>
int main()
{
int number;
std::cin >> number;
while (number % 2 == 0)
{
number = number / 2;
std::cout << 2 << ' ';
}
if (number < 2) return 0;
for (int i = 3; i <= std::sqrt(number); i+=2)
{
if (number % i == 0)
{
number /= i;
std::cout << i << ' ';
i -= 2;
}
}
if (number > 2) std::cout << number << std::endl;
return 0;
}
2.1.3 根据质数分布规律优化
#include <iostream>
#include <cmath>
#include <set>
bool isPrime(int value)
{
if (value == 2 || value == 3)
return true;
/*
* 质数分布规律:
* 1. 质数一定分布在6的倍数的两侧,如5,7,11,13等;
* 2. 6的倍数的两侧不一定都是质数。
*/
if (value % 6 != 1 && value % 6 != 5)
return false;
int size = sqrt(value);
for (int i = 5; i <= size; i+=6)
{
if (value % i == 0 || value % (i + 2) == 0)
return false;
}
return true;
}
int main()
{
int n = 0;
std::cin >> n;
std::set<int> set = { 2 };
int number = n;
for (int i = 3; i < n; i++)
{
if (isPrime(i))
{
set.insert(i);
}
}
int min = number;
std::pair<int, int> value;
for (auto& item : set)
{
if (set.find(number - item) != set.end())
{
if (std::fabs(number - 2 * item) < min)
{
min = std::fabs(number - 2 * item);
value = { std::min(number - item,item),std::max(number - item,item) };
}
}
}
std::cout << value.first << "\n" << value.second;
}
2.2 排序算法
2.2.1 排序算法,稳定的排序,要求时间O(nlogn),空间O(n)。
https://zhuanlan.zhihu.com/p/36274119
#include <iostream>
#include <vector>
#include <algorithm>
bool compare_1(const std::pair<std::string, std::pair<float, int>>& a, const std::pair<std::string, std::pair<float, int>>& b)
{
if (a.second.first < b.second.first)
{
return true;
}
else if (a.second.first == b.second.first && a.second.second < b.second.second)
{
return true;
}
return false;
}
bool compare_0(const std::pair<std::string, std::pair<float, int>>& a, const std::pair<std::string, std::pair<float, int>>& b)
{
if (a.second.first > b.second.first)
{
return true;
}
else if (a.second.first == b.second.first && a.second.second < b.second.second)
{
return true;
}
return false;
}
int main()
{
std::vector<std::pair<std::string, std::pair<float, int>>> values;
int n = 0, m = 0;
std::cin >> n >> m;
for (int i = 0; i < n; i++)
{
std::pair<std::string, std::pair<float, int>> value;
std::cin >> value.first >> value.second.first;
value.second.second = i;
values.push_back(value);
}
if(m == 0)
std::sort(values.begin(), values.end(), compare_0);
else if (m == 1)
std::sort(values.begin(), values.end(), compare_1);
for (auto& item : values)
{
std::cout << item.first << " " << item.second.first << std::endl;
}
return 0;
}
2.2 杨辉三角
#include <iostream>
#include <vector>
int main()
{
int n = 0;
std::cin >> n;
if (n < 3)
{
std::cout << "-1";
return 0;
}
std::vector<int> data1 = { 1,1,1 };
std::vector<int> data2;
for (int i = 3; i <= n; i++)
{
data2.resize(2 * i - 1, 0);
data2[0] = data2[data2.size() - 1 ] = 1;
data2[1] = data2[data2.size() - 2] = data1[0] + data1[1];
for (int k = 2; k <= data2.size() - 3; k++)
{
data2[k] = data1[k - 2] + data1[k - 1] + data1[k];
}
data1 = data2;
}
int index = -1;
for (int i = 0; i < n; i++)
{
if (data2[i] % 2 == 0)
{
index = i + 1;
break;
}
}
std::cout << index;
return 0;
}
#include <iostream>
#include <vector>
/*
* 出现偶数的位置规律如下:
* 1----2----3----4----5----6----7----8----9----10----11----12 ...
*
*-1 -1 2 3 2 4 2 3 2 4 2 3
*/
int getIndex(int n)
{
if (n < 3) return -1;
int value = (n - 2) % 4;
int index = -1;
switch (value)
{
case 1:index = 2; break;
case 2:index = 3; break;
case 3:index = 2; break;
case 0:index = 4; break;
default: break;
}
return index;
}
int main()
{
int n = 0;
std::cin >> n;
//->找规律
std::cout << getIndex(n);
return 0;
//->常规解法,超时
if (n < 3)
{
std::cout << "-1";
return 0;
}
std::vector<int> data(2 * n - 1, 0);
data[n - 1] = data[n - 2] = data[n] = 1;
for (int i = 3; i <= n; i++)
{
data[n - i] = data[n + i - 2] = 1;
int back2Value = data[n + i - 3];
int value0 = data[n - i + 1];
int value1 = 0, value2 = 0;
data[n - i + 1] = data[n + i - 3] = data[n - i + 2] + data[n - i + 1];
for (int k = n - i + 2; k <= n + i - 4; k++)
{
value1 = data[k];
value2 = data[k + 1];
if (k == n + i - 4)
{
value2 = back2Value;
}
data[k] = value0 + data[k] + value2;
value0 = value1;
value1 = data[k + 1];
}
}
int index = -1;
for (int i = 0; i < n; i++)
{
if (data[i] % 2 == 0)
{
index = i + 1;
break;
}
}
std::cout << index;
return 0;
}
三、动态规划
3.1 01背包问题
https://zhuanlan.zhihu.com/p/93857890
https://valen.blog.csdn.net/?type=blog
3.1.1 核心解读
假设物品数量N,限重W的情况下,定义dp[i][j]表示将前i个物品装入限重为j的背包中的最大价值,其中0<=i<=N,0<=j<=W。
- 当i = 0时,装入背包中的总价值为0,即dp[0][0~W] = 0;
- 当i > 0时,有如下两种情况:
- 不装入第i件物品,即[dp[i][j] = dp[i - 1][j];
- 装入第i件物品,即dp[i][j] = dp[i - 1][j - w[i]] + v[i];
则状态转移方程为:
dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - w[i]] + v[i]),其中j >= w[i]。
3.1.2 对于完全背包问题,即每种物品有无限个,则转移状态方程为:
- 当i = 0时,装入背包中的总价值为0,即dp[0][0~W] = 0;
- 当i > 0时,有如下两种情况:
- 不装入第i件物品,即[dp[i][j] = dp[i - 1][j];
- 装入第i件物品,即dp[i][j] = dp[i][j - w[i]] + v[i]; 表示装入第i中商品后还可以继续装入第i中商品。
dp[i][j] = max(dp[i - 1][j],dp[i][j - w[i]] + v[i]),其中j >= w[i]。
思路二:01背包问题,装入物品i只有0件和1件,二完全背包问题,装入第i件物品可以取值0,1,W / w[i];因此状态转移方程为:
dp[i][j] = max(dp[i - 1][j],dp[i][j - k * w[i]] + v[i]),其中j >= k* w[i],k<=j /w[i];
3.1.3 例题
#include <iostream>
#include <map>
#include <vector>
struct Data
{
int price, nice;
};
int main()
{
int W = 0, N = 0;
std::cin >> W >> N;
std::map<int, std::vector<Data>> product;
std::map<int, bool> visited;
for (int i = 0; i < N; i++)
{
int price, weight, index;
std::cin >> price >> weight >> index;
Data data;
data.price = price;
data.nice = price * weight;
if (index == 0)
{
if (product.find(i) == product.end())
product[i].push_back(data);
else
{
product[i].insert(product[i].begin(), data);
for (int j = 1; j < product[i].size(); j++)
{
Data temp;
temp.price = data.price + product[i][j].price;
temp.nice = data.nice + product[i][j].nice;
product[i][j] = temp;
}
}
visited[i] = true;
}
else
{
if (product[index - 1].size() == 0)
{
product[index - 1].push_back(data);
continue;
}
//->将附件与主件进行组合
for (int j = 0, size = product[index - 1].size(); j < size; j++)
{
Data temp;
temp.price = data.price + product[index - 1][j].price;
temp.nice = data.nice + product[index - 1][j].nice;
product[index - 1].push_back(temp);
}
if (product[index - 1].size() != 0 && !visited[index - 1])
{
product[index - 1].push_back(data);
}
}
}
//->将商品数量索引与map的it迭代器进行映射
int index = 0;
std::map<int, std::map<int, std::vector<Data>>::iterator> mapping;
for (auto it = product.begin(); it != product.end(); it++)
{
mapping[index] = it;
index++;
}
//->核心算法
std::vector<std::vector<int>> ks(product.size() + 1, std::vector<int>(W + 1, 0));
for (int i = 1; i < ks.size(); i++)
{
for (int j = 0; j < ks[i].size(); j++)
{
for (int k = 0; k < mapping[i - 1]->second.size(); k++)
{
if (j - mapping[i - 1]->second[k].price >= 0)
ks[i][j] =
std::max(ks[i][j], ks[i - 1][j - mapping[i - 1]->second[k].price] + mapping[i - 1]->second[k].nice);
else
ks[i][j] = ks[i - 1][j];
}
}
}
std::cout << ks[product.size()][W] << std::endl;
}
四、回溯法
4.1迷宫路径搜索
4.1.1 采用回溯法搜索迷宫中的路径。
将数组大小设置(N + 2) x (M + 2), 并设置最外围为1,简化代码判断逻辑。
#include<vector>
#include <iostream>
#include <stack>
bool FindPath(std::vector<std::vector<int>>& data, std::vector<std::vector<int>>& mark, int x, int y, int i, int j, std::stack<std::pair<int,int>>& path)
{
if (x == i && y == j)
return true;
std::vector<std::pair<int, int>> move = { {-1,0},{1,0},{0,-1},{0,1} };
for (int k = 0; k < move.size(); k++)
{
int next_i = i + move[k].first;
int next_j = j + move[k].second;
if (data[next_i][next_j] == 0 && mark[next_i][next_j] == 0)
{
mark[next_i][next_j] = 1;
if (FindPath(data, mark, x, y, next_i, next_j,path))
{
path.push({ next_i,next_j });
return true;
}
}
}
if (x == 1 && y == 1)
return false;
return false;;
}
int main()
{
int n = 0, m = 0;
std::cin >> n >> m;
std::vector<std::vector<int>> data = std::vector<std::vector<int>>(n + 2, std::vector<int>(m + 2, 1));
std::vector<std::vector<int>> mark = std::vector<std::vector<int>>(n + 2, std::vector<int>(m + 2, 0));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
std::cin >> data[i][j];
}
}
std::stack<std::pair<int, int>> path;
mark[1][1] = 1;
int value = FindPath(data, mark, n, m, 1, 1, path);
path.push({ 1,1 });
while (!path.empty())
{
std::pair<int, int> node = path.top();
std::cout << "(" << node.first - 1 << "," << node.second - 1 << ")" << std::endl;
path.pop();
}
return 0;
}
4.2 九宫格游戏
#include<vector>
#include <iostream>
bool row(std::vector<std::vector<int>>& data, int i, int value)
{
for (int k = 0; k < 9; k++)
{
if (data[i][k] == value) return false;
}
return true;
}
bool col(std::vector<std::vector<int>>& data, int j, int value)
{
for (int k = 0; k < 9; k++)
{
if (data[k][j] == value) return false;
}
return true;
}
bool region(std::vector<std::vector<int>>& data, int i, int j, int value)
{
int istart = i / 3 * 3;
int jstart = j / 3 * 3;
for (int m = istart; m < istart + 3; m++)
{
for (int n = jstart; n < jstart + 3; n++)
{
if (data[m][n] == value)
return false;
}
}
return true;
}
void output(std::vector<std::vector<int>>& data)
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
std::cout << data[i][j] << " ";
}
std::cout << std::endl;
}
// 调试用
//std::cout << std::endl;
//std::system("pause");
}
bool FindNumber(std::vector<std::vector<int>>& data, int index, std::vector<std::pair<int,int>>& position, std::vector<bool>& visited)
{
if (index == position.size())
return true;
if (index < 0 || index > position.size())
return false;
std::vector<int> values;
for (int v = 1; v <= 9; v++)
{
if (!row(data, position[index].first, v))
continue;
if (!col(data, position[index].second, v))
continue;
if (!region(data, position[index].first, position[index].second, v))
continue;
values.push_back(v);
}
if (values.empty() && index < position.size())
return false;
int count = 0;
for (auto& v : values)
{
data[position[index].first][position[index].second] = v;
//output(data);
if (FindNumber(data, index + 1, position, visited))
{
data[position[index].first][position[index].second] = v;
return true;
}
else
{
count++;
}
}
if (count == values.size())
{
data[position[index].first][position[index].second] = 0;
return false;
}
return true;
}
int main()
{
/*
0 9 5 0 2 0 0 6 0
0 0 7 1 0 3 9 0 2
6 0 0 0 0 5 3 0 4
0 4 0 0 1 0 6 0 7
5 0 0 2 0 7 0 0 9
7 0 3 0 9 0 0 2 0
0 0 9 8 0 0 0 0 6
8 0 6 3 0 2 1 0 5
0 5 0 0 7 0 2 8 3
*/
std::vector<std::vector<int>> data = std::vector<std::vector<int>>(9, std::vector<int>(9, 0));
std::vector<std::pair<int, int>> position;
std::vector<bool> visited;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
std::cin >> data[i][j];
if (data[i][j] == 0)
{
position.push_back({ i,j });
visited.push_back(false);
}
}
}
bool value = false;
for (int i = 0; i < position.size(); i++)
{
value = FindNumber(data, 0, position, visited);
if (value) break;
}
output(data);
return 0;
}