解题思路:
首先,我们需要明确最小割的定义:最少的边的数量,需满足删除这些边后图会变成不连通的两部分。
我们可以利用最小割的性质来解决这个问题。最小割的性质是:如果我们将图G中的一个顶点集合分为两个不相交的子集合,然后计算通过这两个子集合的边的权重之和,那么这个权重之和就是最小割的权重。
具体步骤如下:
- 构建图G的邻接矩阵,用一个二维数组来表示。
- 遍历TT中的每一条边,将其权重设为无穷大,表示这些边不能被删除。
- 遍历剩余的边,将其权重设置为1,表示这些边可以被删除。
- 对于每个顶点集合的划分,计算通过这两个子集合的边的权重之和,取最小值即为最小割的权重。
- 输出最小割的权重。
代码如下:
#include
#include
#include
#include
using namespace std;
// 广度优先搜索,判断顶点v是否在集合S中
bool bfs(vector<vector>& graph, int v, vector& S) {
queue q;
q.push(v);
vector visited(graph.size(), false);
visited[v] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < graph[u].size(); i++) {
int w = graph[u][i];
if (!visited[w] && S[w] == S[u]) {
visited[w] = true;
q.push(w);
}
}
}
for (int i = 0; i < S.size(); i++) {
if (S[i] == S[v] && !visited[i]) {
return false;
}
}
return true;
}
// 最小割算法,返回最小割的权重
int minCut(vector<vector>& graph) {
int n = graph.size();
vector S(n, 0);
int mincut = INT_MAX;
for (int i = 0; i < n; i++) {
S[i] = i;
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (graph[i][j] == 0) {
continue;
}
S[j] = 1 - S[j];
if (bfs(graph, i, S)) {
int cut = 0;
for (int k = 0; k < n - 1; k++) {
for (int l = k + 1; l < n; l++) {
if (S[k] != S[l] && graph[k][l] > 0) {
cut++;
}
}
}
mincut = min(mincut, cut);
}
}
}
return mincut;
}
int main() {
int T;
cin >> T;
while (T--) {
int N, M;
cin >> N >> M;
vector<vector> graph(N, vector(N, 0));
for (int i = 0; i < N - 1; i++) {
int u, v;
cin >> u >> v;
graph[u - 1][v - 1] = 1;
graph[v - 1][u - 1] = 1;
}
for (int i = 0; i < M - N + 1; i++) {
int u, v;
cin >> u >> v;
graph[u - 1][v - 1] = 1;
graph[v - 1][u - 1] = 1;
}
int mincut = minCut(graph);
cout << mincut << endl;
}
return 0;