Skip to content

JZOJ - 5806. 简单的操作

题解983 字
检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#题面

#题目描述

有个包含 nn 个点,mm 条边,无自环和重边的无向图。

对于两个没有直接连边的点 u,vu, v,你可以将它们合并。具体来说,你可以删除 u,vu, v 及所有以它们作为端点的边,然后加入一个新点 xx,将它与所有在原图中与 uuvv 直接连边的点连边。

你需要判断是否能通过若干次合并操作使得原图成为一条链,如果能,你还需要求出这条链的最大长度。

#输入格式

第一行两个正整数 n,mn, m,表示图的点数和边数。

接下来 mm 行,每行两个正整数 u,vu, v,表示 uuvv 之间有一条无向边。

#输出格式

如果能通过若干次合并操作使得原图成为一条链,输出链的最大长度,否则输出$ -1 $

#输入输出样例

样例输入 #1

5 4
1 2
2 3
3 4
3 5

样例输出 #1

3

样例解释 #1

只要合并 4455 就变成一条长度为 33 的链。

样例输入 #2

4 6
1 2
2 3
1 3
3 4
2 4
1 4

样例输出 #2

-1

#数据范围与约定

对于 30%30\% 的数据,n10n \leq 10
对于 70%70\% 的数据,m2000m \leq 2000
对于 100%100\% 的数据,n1000n \leq 1000m105m \leq 10^5

#思路

先考虑整张图连通的情况。

如果原图不是二分图则无解,因为对于一个长度大于 33 的奇环,如果合并环上任意两个不相邻的点,一定会生成一个更小的奇环,最后剩下一个无法继续合并的三元环,无法满足题目要求。

那么对于任意一个联通的二分图,可以钦定一个点 ss,然后将所有与 ss 距离相同的点合并。由于原图是二分图,所有与 ss 联通的点必然在同一个点集中(两点间一定不会直接相连),这样就可以构造出一条最长链了。这条最长链的长度就是这个图的直径。

再考虑整张图有多个连通分量的情况。

对于每个连通分量都可以构造出一条链,然后再将这些链合并成一条长链即可,这条长链的长度为所有连通分量的直径之和。

#代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <iostream>
#include <queue>
#include <stack>
#include <unordered_set>
#include <utility>
#include <vector>

using std::cin;
using std::cout;
const char endl = '\n';

const int N = 1005;

int n, m, color[N], ans;
int cnt, id[N];
bool vis[N];
std::vector<int> g[N];
std::unordered_set<int> p[N];

bool dfs1(int u, int c) {
color[u] = c;

for (int v : g[u]) {
if (color[v]) {
if (color[v] == c) return false;
} else if (!dfs1(v, 3 - c)) {
return false;
}
}

return true;
}

bool check() {
for (int i = 1; i <= n; i++) {
if (!color[i]) {
if (!dfs1(i, 1)) return false;
}
}

return true;
}

void dfs2(int u, int x) {
id[u] = x;
p[x].insert(u);

for (int v : g[u]) {
if (!id[v]) dfs2(v, x);
}
}

int bfs(int x) {
std::fill_n(vis, N, false);

int res = 0;

std::queue<std::pair<int, int>> q;

q.emplace(x, 0);
vis[x] = true;

while (!q.empty()) {
auto e = q.front();
q.pop();

int u = e.first,
w = e.second;

res = std::max(res, w);

for (int v : g[u]) {
if (vis[v]) continue;
vis[v] = true;

q.emplace(v, w + 1);
}
}

return res;
}

int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr);

cin >> n >> m;

for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;

g[u].emplace_back(v);
g[v].emplace_back(u);
}

if (!check()) {
cout << -1 << endl;

exit(0);
}

for (int i = 1; i <= n; i++) {
if (!id[i]) dfs2(i, ++cnt);
}

for (int i = 1; i <= cnt; i++) {
int res = 0;

for (const int &x : p[i]) {
res = std::max(res, bfs(x));
}

ans += res;
}

cout << ans << endl;

return 0;
}