1.最短距离
题目简化:
明确问题 + 算法提示:
1.如何判断同类之间的最短距离为0 ---> 并查集+路径压缩
2.如何存储任意两类的距离 ---> 邻接矩阵存储无向图
3.如何表示每个点属于哪一类 ---> 用数组id[节点]存储属于哪一类
4.如何算出任意两类之间的最短距离 ---> 最短路问题:Floyd算法(多源汇最短路,多个起点)[动态规划]
详细思路:
并查集+路径压缩
int find(int x)
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}
Floyd算法
for (int t = 1; t <= k; t ++)
{for (int i = 1; i <= k; i ++){for (int j = 1; j <= k; j ++){d[i][j] = min(d[i][j], d[i][t] + d[t][j]);}}
}
代码:
#include <iostream>
#include <cstring>using namespace std;const int N = 1e5 + 10, M = 510, INF = 0x3f3f3f3f;
int p[N], id[N];
int d[M][M]; //两个类之间的距离
int n, m, k;int find(int x)
{if (p[x] != x) p[x] = find(p[x]);return p[x];
}
bool check()
{for (int i = 2; i <= n; i ++)if (id[i] == id[i - 1] && find(i) != find(i - 1))return false;return true;
}
int main()
{cin >> n >> m >> k;for (int i = 1; i <= n; i ++) p[i] = i;for (int i = 1, j = 1; i <= k; i ++) {int c;cin >> c;while (c --) id[j ++] = i;}memset(d, 0x3f, sizeof d);for (int i = 1; i <= k; i ++ ) d[i][i] = 0;for (int i = 1; i <= m; i ++){int u, v, x;cin >> u >> v >> x;if (!x) p[find(u)] = find(v);int a = id[u], b = id[v];d[a][b] = d[b][a] = min(d[a][b], x);}if (!check()) puts("No");else{puts("Yes");for (int t = 1; t <= k; t ++){for (int i = 1; i <= k; i ++){for (int j = 1; j <= k; j ++){d[i][j] = min(d[i][j], d[i][t] + d[t][j]);}}}for (int i = 1; i <= k; i ++){for (int j = 1; j <= k; j ++){if (d[i][j] == INF) d[i][j] = -1;cout << d[i][j] << ' ';}cout << endl;}}
}
2.奶牛报数
题目简化:
将这n头牛按顺时针围成一个圈,然后选定一头牛开始从1报数,所有的牛报完数,每一头牛都有相应的报的数字,当报到的数落在[l, r)区间中,则表示该牛被选中制作牛肉
限制条件:所选牛的重量总和最大且第一头牛所报的数尽量小的方案
求:第一头牛所报的数
明确问题 + 算法提示:
1.如何表示按顺时针围成一圈的牛?---> 破环成链
2.如何算出报数在区间内牛的重量总和?---> 区间和:前缀和
3.如何算出第一头牛所报的数? ---> 通过第i头牛报的数,算出第1头牛所报的数
图解分析:
代码:
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;const int N = 1e5 + 10;
int n, l, r;
int a[2 * N], s[2 * N];int main()
{cin >> n;for (int i = 1; i <= n; i ++){cin >> a[i];a[i + n] = a[i];}//求前缀和for (int i = 1; i <= 2 * n; i ++) s[i] = s[i - 1] + a[i];cin >> l >> r;int len = r - l, res = -1, ans = 0;for (int i = 1; i <= 2 * n - len; i ++){int sum = s[i + len - 1] - s[i - 1], idx = l - i + 1;while (idx < 1) idx += n;if (sum > ans || sum == ans && idx < res){res = idx;ans = sum;}}cout << res << endl;
}
3.机器人跳跃问题
题目简化:
机器人初始有能量值e,机器人需要跳跃n个建筑,每个建筑有对应的高度,第i个建筑的高度
为h[i],机器人每次跳跃当前建筑,所花费的代价为e - h[i](即当e > h[i]时,能量增加e - h[i];当e < h[i]时,能量减少e - h[i]), 在每次跳跃后要保证能量值不能为负数
图示分析:
算法:递推 + 二分查找
代码:
#include <iostream>
#include <algorithm>using namespace std;const int N = 1e5 + 10;
int n, h[N];bool judge(int e)
{for (int i = 1; i <= n; i ++){e = 2 * e - h[i];if (e < 0) return false;if (e >= N) return true;}return true;
}
int main()
{scanf ("%d", &n);for (int i = 1; i <= n; i ++) scanf ("%d", &h[i]);int l = 0, r = N;while (l < r){int mid = (l + r) / 2;if (judge(mid)) r = mid;else l = mid + 1; }cout << l << endl;return 0;
}
注意:题目均来自AcWing
所有笔记总结目录-CSDN博客