6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出样例:
22
// https://www.acwing.com/activity/content/code/content/1215928/
#include
#include
#include
using namespace std;
const int N = 10010, M = N * 2;
int n;
int h[N], e[M], w[M], ne[M], idx;
int ans;
void add(int a, int b, int c) {
e[++idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx;
}
int dfs(int u, int father) {
int dist = 0; // 表示从当前点往下走的最大长度
int d1 = 0, d2 = 0;
for (int i = h[u]; i; i = ne[i]) {
int j = e[i];
if (j == father)
continue;
int d = dfs(j, u) + w[i];
dist = max(dist, d);
if (d >= d1)
d2 = d1, d1 = d;
else if (d > d2)
d2 = d;
}
ans = max(ans, d1 + d2);
return dist;
}
int main() {
cin >> n;
for (int i = 0; i < n - 1; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dfs(1, -1);
cout << ans << endl;
return 0;
}
5
2 1 1
3 2 1
4 3 1
5 1 1
输出样例:
2
// https://www.acwing.com/activity/content/code/content/1219105/
#include
#include
#include
using namespace std;
const int N = 1e5 + 5, INF = 1e9;
int d1[N], d2[N], up[N];
int p1[N], p2[N];
int h[N], ne[2 * N], e[2 * N], idx, w[N];
int n;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int dfs_down(int u, int father) {
//返回u的最长向下路径
d1[u] = d2[u] = -INF;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father)
continue;
int dist = dfs_down(j, u) + w[i];
if (dist > d1[u]) {
//更新一下最长和第二长的路径,并记录下从该路径是从哪一个点下去的
d2[u] = d1[u], d1[u] = dist;
p2[u] = p1[u], p1[u] = j;
} else if (dist > d2[u]) {
d2[u] = dist, p2[u] = j;
}
}
if (d1[u] == -INF)
d1[u] = d2[u] = 0; //如果没有改变过该点的距离,就证明这个点是叶节点
return d1[u];
}
void dfs_up(int u, int father) {
//用父节点更新一下子节点向上的最长路径
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == father)
continue;
if (p1[u] == j)
up[j] = max(up[u], d2[u]) + w[i]; //如果从父节点向下的最长路径进过了要更新的子节点,那么就用第二长的路径更新
else
up[j] = max(up[u], d1[u]) + w[i];
dfs_up(j, u);
}
}
int main() {
cin >> n;
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dfs_down(1, -1);
dfs_up(1, -1);
int res = INF;
for (int i = 1; i <= n; i++)
res = min(res, max(d1[i], up[i]));
cout << res;
}
// https://www.acwing.com/activity/content/code/content/1219611/
#include
#include
#include
using namespace std;
const int N = 50010, M = N;
int n;
int h[N], e[M], w[M], ne[M], idx;
int sum[N];
bool st[N];
int ans;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dfs(int u) {
st[u] = true;
int dist = 0;
int d1 = 0, d2 = 0;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!st[j]) {
int d = dfs(j);
dist = max(dist, d);
if (d >= d1)
d2 = d1, d1 = d;
else if (d > d2)
d2 = d;
}
}
ans = max(ans, d1 + d2);
return dist + 1;
}
int main() {
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i++)
for (int j = 2; j <= n / i; j++)
sum[i * j] += i;
for (int i = 2; i <= n; i++)
if (sum[i] < i)
add(sum[i], i);
for (int i = 1; i <= n; i++)
if (!st[i]) {
dfs(i); // 只需要dfs(1)即可
break;
}
cout << ans << endl;
return 0;
}
5 2
1 3 1
1 4 10
2 3 20
3 5 20
输出样例:
21
// https://www.acwing.com/activity/content/problem/content/1305/1/
#include
#include
#include
using namespace std;
const int N = 110, M = N * 2;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int f[N][N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u, int father)
{
for (int i = h[u]; ~i; i = ne[i])
{
if (e[i] == father) continue;
dfs(e[i], u);
for (int j = m; j; j -- )
for (int k = 0; k + 1 <= j; k ++ )
f[u][j] = max(f[u][j], f[u][j - k - 1] + f[e[i]][k] + w[i]);
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
for (int i = 0; i < n - 1; i ++ )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
dfs(1, -1);
printf("%d\n", f[1][m]);
return 0;
}
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
输出样例:
1
2
#include
#include
#include
using namespace std;
const int N = 1510;
int n;
int h[N], e[N], ne[N], idx;
int f[N][2];
bool st[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u)
{
f[u][0] = 0, f[u][1] = 1;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
dfs(j);
f[u][0] += f[j][1];
f[u][1] += min(f[j][0], f[j][1]);
}
}
int main()
{
while (cin >> n)
{
memset(h, -1, sizeof h);
idx = 0;
memset(st, 0, sizeof st);
for (int i = 0; i < n; i ++ )
{
int id, cnt;
scanf("%d:(%d)", &id, &cnt);
while (cnt -- )
{
int ver;
cin >> ver;
add(id, ver);
st[ver] = true;
}
}
int root = 0;
while (st[root]) root ++ ;
dfs(root);
printf("%d\n", min(f[root][0], f[root][1]));
}
return 0;
}
6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
输出样例:
25
样例解释:
在2、3、4结点安排护卫,可以观察到全部宫殿,所需经费最少,为 16 + 5 + 4 = 25。
这个题初看与AcWing 323. 战略游戏 ,但是仔细分析,发现战略游戏的不选的点中间最多只能空一个,所以只需要记录两个状态,但是这个题可以出现不选的点中间只能空;两个,例如A->B->C->D,可以选择A和D,所以这里需要记录三个状态
* 分为3种状态
* f[i][0] 表示节点i被父结点看到的所有情况中的最小花费
* f[i][1] 表示节点i被子节点看到的所有情况中的最小花费
* f[i][2] 表示节点i上摆放侍卫的所用情况中的最小花费
*
* 状态计算:
* f[i][0] = min (f[j][2], f[j][1]) 点i是没有侍卫的,因此子节点只能有这两种情况
* f[i][2] = min (f[j][2], f[j][0], f[j][1]) 点i有侍卫,子节点可以被i影响到,因此有3种情况
*
* f[i][1] = min(f[j][1], f[j][2]) + f[k][2]
* 第3种情况较为复杂:如果结点i被子节点看到,那么说明,子节点有侍卫,i没有侍卫
* 那么在所有的集合情况中,应该找到子节点有侍卫的最小花费假定为f[k][2], 再加上其他子节点的花费情况,
* 而其他子节点的情况为min(f[j][1], f[j][2])(由于i没有侍卫,子节点可以表示为放侍卫或者被子节点影响)
*
* 观察第一种状态的计算,f[i][0] = min (f[j][2], f[j][1]),
* 其实可以得出第3种状态中的min(f[j][1], f[j][2])就相当于f[i][0] 减去 找到的某一个子节点的最小花费
* (因为第一种状态是包含了所有子节点的情况, 而当前找出除开某个子节点的其他情况)
* (在这种情况下,要除去的子节点的最小花费下相当于min(f[j][1], f[j][2]), 因为父亲节点是没有侍卫的)
* 因此 f[i][1] = min (f[i][1], f[i][0] - min(f[j][1], f[j][2]) + f[j][2])
// https://www.acwing.com/activity/content/code/content/1222553/
#include
#include
#include
using namespace std;
const int N = 1510;
int n;
int h[N], w[N], e[N], ne[N], idx;
int f[N][3];
bool st[N];
void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs(int u)
{
f[u][2] = w[u];
int sum = 0;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
dfs(j);
f[u][0] += min(f[j][1], f[j][2]);
f[u][2] += min(min(f[j][0], f[j][1]), f[j][2]);
sum += min(f[j][1], f[j][2]);
}
f[u][1] = 1e9;
for (int i = h[u]; ~i; i = ne[i])
{
int j = e[i];
f[u][1] = min(f[u][1], sum - min(f[j][1], f[j][2]) + f[j][2]);
}
}
int main()
{
cin >> n;
memset(h, -1, sizeof h);
for (int i = 1; i <= n; i ++ )
{
int id, cost, cnt;
cin >> id >> cost >> cnt;
w[id] = cost;
while (cnt -- )
{
int ver;
cin >> ver;
add(id, ver);
st[ver] = true;
}
}
int root = 1;
while (st[root]) root ++ ;
dfs(root);
cout << min(f[root][1], f[root][2]) << endl;
return 0;
}