Add Edges to Make Degrees of All Nodes Even
There is an undirected graph consisting of $n$ nodes numbered from $1$ to $n$. You are given the integer $n$ and a 2D array edges where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi . The graph can be disconnected.
You can add at most two additional edges (possibly none) to this graph so that there are no repeated edges and no self-loops.
Return true if it is possible to make the degree of each node in the graph even, otherwise return false.
The degree of a node is the number of edges connected to it.
Example 1:
Input: n = 5, edges = [[1,2],[2,3],[3,4],[4,2],[1,4],[2,5]] Output: true Explanation: The above diagram shows a valid way of adding an edge. Every node in the resulting graph is connected to an even number of edges.
Example 2:
Input: n = 4, edges = [[1,2],[3,4]] Output: true Explanation: The above diagram shows a valid way of adding two edges.
Example 3:
Input: n = 4, edges = [[1,2],[1,3],[1,4]] Output: false Explanation: It is not possible to obtain a valid graph with adding at most 2 edges.
Constraints:
$2 \leq \text{edges.length} \leq {10}^{5}$
$\text{edges}[i]\text{.length} \mathrm{==} 2$
$1 \leq a_i, b_i \leq n$
$a_i \ne b_i$
There are no repeated edges.
解题思路
这题就是分类讨论。
首先容易发现加一条边最多可以将两个度数为奇数的结点变成偶数,又因为最多可以加两条边,因此如果图中度数为奇数的结点个数超过$4$个那么就无解。
然后如果要加一条边,那么这条边对应的两个结点的度数有$3$种情况:两个都是奇数、两个都是偶数、一个是奇数一个是偶数。
- 如果给两个度数为奇数的结点连一条边,这两个结点的度数都变成偶数,那么图中度数为奇数的结点的个数就会减少$2$。
- 如果给两个度数为偶数的结点连一条边,这两个结点的度数都变成奇数,那么图中度数为奇数的结点的个数就会增加$2$。
- 如果给两个度数奇偶性不同的结点连一条边,这两个结点的度数依然是一个奇数一个偶数,那么图中度数为奇数的结点的个数不变。
因此可以发现无论怎么连边,图中度数为奇数的结点的个数的奇偶性不会变。又因为最后要保证图中度数为奇数的结点个数为$0$,因此如果图中度数为奇数的结点个数为奇数个,那么无解。事实上度数为奇数的结点个数是奇数这种情况是不可能会发生的。这是因为如果有奇数个度数为奇数的结点,那么把所有结点的度数进行累加后总度数就为奇数,而每条边都与两个结点相连,意味着每条边的度数贡献为$2$,因此总的度数应该为偶数,这就矛盾了。
因此度数为奇数的结点个数可以分成三种情况:$0$、$2$、$4$。
对于$0$的情况,直接返回$\text{true}$。
对于$2$的情况,分连一条边和连两条边的情况。如果要连一条边,那么就应该给这两个结点间连一条边,因为不能有重边,因此只有当这条边不存在才可以连。否则考虑连两条边,在其余的点中找一个点(这个点的度数必然是偶数),然后这个点分别与两个度数为奇数的点连一条边(一样要保证不能有重边)。
对于$4$的情况,此时必然要把这$4$个度数为奇数的点中分成两组,组内两两连一条边。可以通过枚举全排列或者组合来进行分组,只要存在一种分组情况是可以连边的(无重边),那么就有解。
AC代码如下:
1 class Solution { 2 public: 3 bool isPossible(int n, vector<vector<int>>& edges) { 4 vector<int> deg(n + 1); 5 set<pair<int, int>> st; // 哈希表,统计某条边是否出现过 6 for (auto &p : edges) { 7 deg[p[0]]++, deg[p[1]]++; 8 st.insert({p[0], p[1]}), st.insert({p[1], p[0]}); 9 } 10 vector<int> p; 11 for (int i = 1; i <= n; i++) { 12 if (deg[i] & 1) p.push_back(i); // 找到度数为奇数的点 13 } 14 if (p.size() == 0) { 15 return true; 16 } 17 else if (p.size() == 2) { 18 if (!st.count({p[0], p[1]})) return true; // 这两个点之间可以连一条边 19 for (int i = 1; i <= n; i++) { // 找到这两个点之外的点,分别与这两个点连一条边 20 if (i != p[0] && i != p[1] && !st.count({p[0], i}) && !st.count({p[1], i})) return true; 21 } 22 } 23 else if (p.size() == 4) { 24 do { 25 if (!st.count({p[0], p[1]}) && !st.count({p[2], p[3]})) return true; // 组内两点都可以连一条边 26 } while (next_permutation(p.begin(), p.end())); 27 } 28 return false; 29 } 30 };
参考资料
力扣第324场周赛:https://www.bilibili.com/video/BV1wD4y1h7Vz/
标签:Even,度数,结点,奇数,Make,个数,偶数,Add,edges From: https://www.cnblogs.com/onlyblues/p/16990649.html