main
黄海 2 years ago
parent 2f3e4e2f7f
commit 5083079c0e

@ -1,42 +1,49 @@
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
const int N = 110, M = N << 1;
const int INF = 0x3f3f3f3f;
int n;
int a[N], st[N]; // b 数组存是否遍历过这个节点
int e[N][10]; // 存储树
int dis[N][N]; // 存节点间的距离
int cnt;
int x[N]; // 点权权值数组
int st[N]; // st 数组存是否遍历过这个节点
int dis[N][N]; // 存节点间的距离
void dfs(int u, int x) { // x 表示起点
st[u] = 1;
dis[x][u] = cnt, dis[u][x] = cnt;
cnt++;
for (int i = 1; i <= e[u][0]; i++) { // 枚举子节点
if (st[e[u][i]]) continue;
dfs(e[u][i], x);
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dfs(int root, int u, int step) { // root 表示根,u:当前走到哪个节点step:到u点时走了几步
st[u] = 1; // u走过了防止回头路
dis[root][u] = step, dis[u][root] = step; // root<->u之间的路径长度
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (st[v]) continue;
dfs(root, v, step + 1);
}
cnt--; // 退回上一个节点,要记得把距离减去一
}
int main() {
// 初始化链式前向星
memset(h, -1, sizeof h);
cin >> n;
for (int i = 1; i <= n; i++) {
int x, y;
cin >> a[i] >> x >> y;
if (x) e[i][++e[i][0]] = x, e[x][++e[x][0]] = i; // 存图
if (y) e[i][++e[i][0]] = y, e[y][++e[y][0]] = i;
int a, b;
cin >> x[i] >> a >> b;
if (a) add(i, a), add(a, i); // 存图
if (b) add(i, b), add(b, i);
}
for (int i = 1; i <= n; i++) {
memset(st, 0, sizeof st);
cnt = 0; // 初始化
dfs(i, i); // 搜索
dfs(i, i, 0); // 搜索
}
int ans = INF;
for (int i = 1; i <= n; i++) {
int s = 0;
for (int j = 1; j <= n; j++)
s = s + a[j] * dis[i][j]; // 累加距离
s = s + x[j] * dis[i][j]; // 累加距离
ans = min(ans, s);
}
cout << ans << endl;

@ -284,10 +284,64 @@ $n$ 的值很小,最多可以有 $O(n^3)$ 的时间复杂度。
这样就需要求出节点之间的距离。先枚举起点,然后算出每个节点到这个起点间的距离。我用的是一个朴素的 $dfs$,在搜索的过程中累加距离,每搜索到一个节点,就储存这个节点与起点间的距离。
而累加距离也很容易实现,在从一个节点遍历到下一个节点时,$cnt$ 增加 $1$;而退回上一个节点时,$cnt$ 减去 $1$。
而累加距离也很容易实现,在从一个节点遍历到下一个节点时,$step$ 增加 $1$
代码就很好实现了,时间复杂度也不高,$O(n^2)$。
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = N << 1;
const int INF = 0x3f3f3f3f;
int n;
int x[N]; // 点权权值数组
int st[N]; // st 数组存是否遍历过这个节点
int dis[N][N]; // 存节点间的距离
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
void dfs(int root, int u, int step) { // root 表示根,u:当前走到哪个节点step:到u点时走了几步
st[u] = 1; // u走过了防止回头路
dis[root][u] = step, dis[u][root] = step; // root<->u之间的路径长度
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (st[v]) continue;
dfs(root, v, step + 1);
}
}
int main() {
// 初始化链式前向星
memset(h, -1, sizeof h);
cin >> n;
for (int i = 1; i <= n; i++) {
int a, b;
cin >> x[i] >> a >> b;
if (a) add(i, a), add(a, i); // 存图
if (b) add(i, b), add(b, i);
}
for (int i = 1; i <= n; i++) {
memset(st, 0, sizeof st);
dfs(i, i, 0); // 搜索
}
int ans = INF;
for (int i = 1; i <= n; i++) {
int s = 0;
for (int j = 1; j <= n; j++)
s = s + x[j] * dis[i][j]; // 累加距离
ans = min(ans, s);
}
cout << ans << endl;
return 0;
}
```
**三、$O(N)$算法**

Loading…
Cancel
Save