J.Graph and Cycles
题意
给定一个 n n n个顶点的无向完全图( n n n为奇数,有 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)条边),每条边 e i ( u , v ) e_i(u,v) ei(u,v)有一个权值 w [ i ] w[i] w[i]。
需要将所有的边分成若干个集合(设集合数量为 m m m),每条边只能属于一个集合 S i S_i Si。
任意一个集合 S i = { e 1 ( u 1 , v 1 ) , e 2 ( u 2 , v 2 ) , e 3 ( u 3 , v 3 ) } S_i=\{e_1(u_1,v_1),e_2(u_2,v_2),e_3(u_3,v_3)\} Si={e1(u1,v1),e2(u2,v2),e3(u3,v3)}需要满足:(这个集合是有一定顺序的,详细的可以看英文题目)
且定义这个集合的权值为:
∑
i
=
1
∣
S
i
∣
−
1
M
a
x
(
w
[
i
]
,
w
[
i
+
1
]
)
+
M
a
x
(
w
[
∣
S
i
∣
]
,
w
[
1
]
)
\sum_{i=1}^{|S_i|-1}Max(w[i],w[i+1])+Max(w[|S_i|],w[1])
i=1∑∣Si∣−1Max(w[i],w[i+1])+Max(w[∣Si∣],w[1])
定义这
m
m
m个集合总的权值为:
∑
i
=
1
m
v
a
l
(
S
i
)
\sum_{i=1}^{m}val(S_i)
∑i=1mval(Si),
v
a
l
(
S
i
)
val(S_i)
val(Si)指集合
S
i
S_i
Si的权值。
问这个总权值的最小值是多少。
思路
题解思路特别巧妙,将边的问题,转化成点的问题。
所有顶点的度数均为偶数,若 e a e_a ea是从 v e r ver ver点进去的边, e b e_b eb是从 v e r ver ver出去的边,则可以将这两条边组成一个 P a i r ( e a , e b ) Pair(e_a,e_b) Pair(ea,eb)。
定义这个 P a i r ( e a , e b ) Pair(e_a,e_b) Pair(ea,eb)属于同一个集合,且 e a e_a ea和 e b e_b eb的公共顶点是 u u u,则该 P a i r ( e a , e b ) Pair(e_a,e_b) Pair(ea,eb)对该集合的贡献是 M a x ( w [ a ] , w [ b ] ) Max(w[a],w[b]) Max(w[a],w[b]),为使最终结果更小,要使得这个值尽可能的小,可以将与点 u u u相连的边从小到大排序然后两两取出(可以感性理解一下,具体证明我就不写了)。
每个顶点都有
n
−
1
2
\frac{n-1}{2}
2n−1对
P
a
i
r
(
e
a
,
e
b
)
Pair(e_a,e_b)
Pair(ea,eb),则对于这个点来说,点
u
u
u对结果的贡献是:
v
a
l
(
u
)
=
∑
i
n
−
1
2
M
a
x
(
w
[
a
i
]
,
w
[
b
i
]
)
val(u)=\sum_{i}^{\frac{n-1}{2}}Max(w[a_i],w[b_i])
val(u)=i∑2n−1Max(w[ai],w[bi])
AC的代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1000 + 10;
int n;
vector<int> vec[N];
int main() {
cin >> n;
for (int i = 1; i <= n * (n - 1) / 2; i++) {
int u, v, w;
cin >> u >> v >> w;
vec[u].push_back(w);
vec[v].push_back(w);
}
for (int i = 1; i <= n; i++) sort(vec[i].begin(), vec[i].end());
ll res = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j < vec[i].size(); j += 2) res += vec[i][j];
cout << res;
return 0;
}