1402 偷懒的小X
题意
给出n个数,把它们放进小根堆里,求出最大的字典序。
思路
考虑将数从小到大放入,那么从父节点到子节点放可保证小根堆的性质。
为了保证字典序最大,从右节点开始放(为了让大的数在左节点),递归填数即可。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
int n, pos;
int a[70001], b[70001];
void dfs(int p, int dep) {
if (p * 2 + 1 <= n && !b[p * 2 + 1]) {
b[p * 2 + 1] = a[++pos];
dfs(p * 2 + 1, pos);
}
if (p * 2 <= n && !b[p * 2]) {
b[p * 2] = a[++pos];
dfs(p * 2, pos);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
std::sort(a + 1, a + n + 1);
b[pos = 1] = a[1];
dfs(1, 1);
for (int i = 1; i <= n; i++)
printf("%d ", b[i]);
}
1403 渡河
题意
给出一个值为(0~1)的矩阵,从0到1的代价为1,求出每个询问的点走到边界的最小代价。
思路
考虑从边界走到询问点,那么用spfa求解最短路即可,注意判断边界上值为1的情况。
代码
#include <queue>
#include <cstdio>
#include <cstring>
const int dx[] = {1, 1, 1, 0, 0, -1, -1, -1}, dy[] = {1, 0, -1, 1, -1, 1, 0, -1};
struct node {
int x, y, w;
};
int n, q, tot;
int a[1001][1001];
int d[1001][1001], v[1001][1001];
char c[1001];
bool operator <(const node &a, const node &b) {
return a.w > b.w;
}
inline int input() {
int res = 0;
char c = getchar();
while (c > '9' || c < '0') c = getchar();
while (c >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - 48, c = getchar();
return res;
}
inline void spfa() {
std::queue<node> q;
memset(d, 127 / 3, sizeof(d));
for (register int i = 1; i <= n; i++) {
q.push((node){1, i, d[1][i] = a[1][i]});
q.push((node){n, i, d[n][i] = a[n][i]});
if (i > 1 && i < n) q.push((node){i, 1, d[i][1] = a[i][1]}), q.push((node){i, n, d[i][n] = a[i][n]});
}
while (q.size()) {
int x = q.front().x, y = q.front().y;
q.pop();
v[x][y] = 0;
for (register int i = 0, verx, very; i < 8; i++) {
verx = x + dx[i];
very = y + dy[i];
if (verx < 1 || verx > n || very < 1 || very > n) continue;
if (d[verx][very] > d[x][y] + (!a[x][y] && a[verx][very])) {
d[verx][very] = d[x][y] + (!a[x][y] && a[verx][very]);
if (!v[verx][very]) {
q.push((node){verx, very, d[verx][very]});
v[verx][very] = 1;
}
}
}
}
}
signed main() {
n = input();
q = input();
for (register int i = 1; i <= n; i++) {
scanf("%s", c);
for (register int j = 1; j <= n; j++)
a[i][j] = c[j - 1] - 48;
}
spfa();
for (register int x, y; q; q--) {
x = input();
y = input();
printf("%d ", d[x][y]);
}
}
1404 菱形内的计数
毒瘤题,未做。
1405 电缆建设
题意
求MST,点的横坐标固定。
思路
由于数据很大,所以普通做法不可取,考虑题目给出的情况。
横坐标固定,故点与点不需要都连边,可发现一个点只用和与它最近的两点以及同一排的两点连边即可。
代码
#include <cmath>
#include <cstdio>
#include <algorithm>
struct node {
int u, v;
double w;
}e[2400001];
int n, m, x1, x2, cnt;
int fa[1200001], p1[600001], p2[600001];
double ans;
int find(int x) {
return fa[x] = fa[x] == x ? x : find(fa[x]);
}
double dis(int a, int b) {
return sqrt((long long)(p1[a] - p2[b]) * (p1[a] - p2[b]) + (long long)(x1 - x2) * (x1 - x2));
}
bool operator <(const node &x, const node &y) {
return x.w < y.w;
}
int main() {
scanf("%d %d %d %d", &n, &m, &x1, &x2);
for (int i = 1, x; i <= n; i++) {
scanf("%d", &x);
p1[i] = p1[i - 1] + x;
if (i > 1) e[++cnt].u = i - 1, e[cnt].v = i, e[cnt].w = x;
fa[i] = i;
}
for (int i = 1, x; i <= m; i++) {
scanf("%d", &x);
p2[i] = p2[i - 1] + x;
if (i > 1) e[++cnt].u = i - 1 + n, e[cnt].v = i + n, e[cnt].w = x;
fa[i + n] = i + n;
}
for (int i = 1, j = 1; i <= n; i++) {
for (; j < m && p1[i] > p2[j]; j++);
e[++cnt].u = i;
e[cnt].v = j + n;
e[cnt].w = dis(i, j);
if (j > 1) {
e[++cnt].u = i;
e[cnt].v = j + n - 1;
e[cnt].w = dis(i, j - 1);
}
}
std::sort(e + 1, e + cnt + 1);
for (int i = 1; i <= cnt; i++) {
int f1 = find(e[i].u), f2 = find(e[i].v);
if (f1 == f2) continue;
fa[f1] = f2;
ans += e[i].w;
}
printf("%.2f", ans);
}

本文精选了三道算法竞赛题目,包括构建小根堆求最大字典序、渡河问题求最小代价路径以及电缆建设中求最小生成树的解决方案。通过深入解析题意和提供代码实现,展示了算法设计和优化技巧。

被折叠的 条评论
为什么被折叠?



