对基础算法类做一个小的总结汇总
1.拼装模型(最小哈夫曼树)
//拼装模型,最小哈夫曼树
#include<iostream>
#include<queue>
using namespace std;
int main() {
priority_queue<int, vector<int>, greater<int>> q;
int n;
cin >> n;
int a;
for (int i = 1; i <= n; i++) {
cin >> a;
q.push(a);
}
int ans = 0;
while (q.size() > 1) {
int a = q.top();
q.pop();
int b = q.top();
q.pop();
ans += a + b;
q.push(a + b);
}
cout << ans << endl; return 0;
}
2.括号配对
//括号配对:这怎么能是个DFS呢
#include<iostream>
using namespace std;
void dfs(int cnt, int n, char *c, int l) {
if (!cnt && !n) {//左括号全都用完,全部括号完成了配对
cout << c << endl;
return;
}
if (cnt < n) {
c[l] = '(';
dfs(cnt + 1, n, c, l + 1);
c[l] = '\0';
}
if (cnt) {//只要有左括号,就要用右括号配上
c[l] = ')';
dfs(cnt - 1, n - 1, c, l + 1);
c[l] = '\0';
}
}
const int maxn = 1000;
int main() {
int n = 0;
char ans[maxn] = "";
cin >> n;
dfs(0, n, ans, 0);
// return 0;
3.扔鸡蛋问题(解法1:DP)
//扔鸡蛋问题
#include<iostream>
#include<cmath>
#include<algorithm>
const int maxn = 100;
using namespace std;
int dp[maxn][maxn];
int n, m;
int main() {
cin >> n >> m;//n是楼层,m是鸡蛋
memset(dp, 0, sizeof(0));
for (int j = 1; j <= n; j++) {
dp[1][j] = j;
}
for (int i = 1; i <= m; i++) {
dp[i][1] = 1;
}
for (int i = 2; i <= m; i++) {
for (int j = 2; j <= n; j++) {
int ans = 10000000;
for (int t = 1; t <= j; t++) {
int temp = max(dp[i - 1][j - t], dp[i][t - 1]);
ans = min(temp, ans);
}
dp[i][j] = 1 + ans;
}
}
cout << dp[m][n]; return 0;
}
解法2(优化DP)
//扔鸡蛋问题的算法优化:i个鸡蛋扔j次,dp[i][j]存的是
#include<iostream>
using namespace std;
int dp[21][901];
int n, m;
int main() {
for (int i = 0; i <=910; i++) {
dp[0][i] = 0;
dp[1][i] = i;
}
for (int i = 1; i <= 20; i++) {
dp[i][0] = 0;
dp[i][1] = 1;
}
for (int i = 2; i <= 20; i++) {
for (int j = 2; j <= 900; j++) {
dp[i][j] = 1 + dp[i - 1][j - 1] + dp[i][j - 1];
}
}
while (cin >> n >> m) {
if (m > 20)m = 20;//大于20一定多于有效鸡蛋数
for (int i = 1; i <= 900; i++) {
if (dp[m][i] <= n && dp[m][i + 1] >= n) {
cout << i + 1 << endl; break;
}
}
}
}
4.子串相似度
(DP)
子串的相似度
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
const int maxn = 100;
string s1, s2;
int dp[maxn][maxn];
int main() {
int n;
cin >> n;
while (n--) {
cin >> s1 >> s2;
int l1 = s1.length();
int l2 = s2.length();
memset(dp, 0, sizeof(dp));
for (int i = 0; i <= l1; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= l2; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= l1; i++) {
for (int j = 1; j <= l2; j++) {
if (s1[i - 1] == s2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1]+1;//lcs中要求必须是连续的
}
else {
dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]),dp[i-1][j-1])+1;//
}
}
}
int dis = dp[l1][l2] + 1;
printf("%.6lf\n", 1 / double(dis));
}
return 0;
}
5.矩阵连乘(DP)(区间dp之先河)
//矩阵连乘:经典区间DP算法默写
#include<iostream>
#include<algorithm>
#include<cmath>
const int maxn = 100;
int p[maxn];
int dp[maxn][maxn];
using namespace std;
int main() {
int n;
cin >> n;
for (int i = 0; i <= n; i++) {
cin >> p[i];
}
memset(dp, 0, sizeof(dp)); int ans;
for (int l = 2; l <= n; l++) {
for (int i = 1; i <= n; i++) {
int j = i + l-1;//就是这里极其奇怪
if (j > n)break;//从根源解决问题
ans = 1 << 30;//大体算法逻辑没问题的话其实主要就是改这两个地方
for (int k = i; k < j; k++) {//保证两侧都取等,根据具体问题可以分析出来
ans = min(ans, dp[i][k] + dp[k + 1][j] + p[i - 1] * p[k]*p[j]);
}
dp[i][j] = ans;
}
}
cout << dp[1][n];
}
6.最小外包矩形
//最小外包矩形
//最小外包矩形
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 10000
int main() {
struct trxy {
int flag;
int xmin;
int xmax;
int ymin;
int ymax;
};
struct trxy t[20];
for (int i = 0; i < 20; i++)
{
t[i] = { 0, N, 0, N, 0 };
}//牵扯到结构体变量的初始化,先定义结构体,再进行初始化
int n;
cin >> n;//太过着急反而忘记了输入
int a = 0; int b = 0; int c = 0;
for (int i = 1; i <= n; i++) {
cin >> a >> b >> c;//用输入的数作为指标,不受循环限制
t[a].flag = 1;
t[a].xmax = max(t[a].xmax, b);
t[a].xmin = min(t[a].xmin, b);
t[a].ymax = max(t[a].ymax, c);
t[a].ymin = min(t[a].ymin, c);
}
for (int i = 1; i < 20; i++) {//对于输出的考量。没说矩形的序号小于等于n;没到序号20别随意输出阿
if (t[i].flag) {//由此也可见结构体确实会自主赋值
cout << i << ' ';
cout << t[i].xmin << ' ' << t[i].ymin << ' ' << t[i].xmax << ' ' << t[i].ymax << endl;
}//越是简单题越要小心,输出是否有误
}
return 0;
}
7.最长平台
最长平台
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100;
int a[N];
int main() {
int n;
while (cin >> n) {
if (n == 0) { cout << endl; return 0; }
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int ans = 0; int x = 1;
for (int i = 1; i < n; i++) {
if (a[i] == a[i - 1]) {
x++;
ans = max(ans, x);
}
else {
x = 1;
}
}
cout << ans << endl;
}
}
8.最长非负子区间
//最长非负子区间;加入循环子区间(其实就是把数组个数+1)
//这题还可以练习一下持续输入,这种题需要每次把数组清零
#include<iostream>
#include<algorithm>
#include<cmath>
const int N = 1000;
int a[N]; int b[N]; int s[N];
using namespace std;
int main() {
int n;
while (cin >> n) {
for (int i = 0; i < n; i++) {
cin >> a[i] >> b[i];
s[i] = a[i] - b[i];
s[n + i] = s[i];
}
int ans = 0; int sum = 0; int num = 0;
for (int i = 0; i < 2 * n; i++) {
sum += s[i];//每每取负,从新开始,因为不可能出现前面少几个负数结果更大的(画个图演示以下即可),否则这在前面就会因为sum《0被清除,优有点像最长子序列和
num++;
if (sum < 0) {
num = 0; sum = 0;
}
ans = max(ans, num);
}
cout << min(n, ans) << endl;//最大就是n了,但是因为上述是加了一个圈,可能超过n减去取最小即可
}
}