实验主题
图的最大匹配
实验目的
1、掌握最大匹配,交错路径的定义;
2、掌握最大匹配的求解方法。
实验要求
输入:无向简单连通图的关联矩阵(例如:)。
输出:此图的最大匹配 例如:M={e1,e3}
实验内容和实验步骤
根据分析,可以通过交错路径求解,只需要枚举出任意两点间的路径,再取其中最长的路径作为交错路径,即可求出最大匹配。匹配数为最长路径中的点数除以2,只保留商即可。
枚举出所有的路径可以采用dfs实现
# 找到所有点的邻接节点,方便用dfs搜索路径
adpoints = {i: [] for i in range(v_count)}
for each in m:
p = list(filter(lambda x: x[1] == 1, enumerate(each)))
adpoints[p[0][0]].append(p[1][0])
adpoints[p[1][0]].append(p[0][0])
result = []
visited = [False] * v_count
# dfs搜索从start点开始的所有路径
def search(visited, start, re):
vi = copy.deepcopy(visited)
vi[start] = True
r = copy.deepcopy(re)
r.append(start)
flag = True
for i in adpoints[start]:
if not vi[i]:
flag = False
search(vi, i, r)
if flag:
result.append(r)
# 搜索每一个点开始的路径
for i in range(v_count):
search(visited, i, re=[])
再通过路径中的点找到对应的交错路径中应该取的边,可以将点两两为一组,一个作为起点一个作为终点,如果还剩余一个点,说明路径长度为偶数,这个点可以舍弃。
# 路径按长度排序
s = sorted(result, key=lambda x: len(x), reverse=True)
print("匹配数=", len(s[0]) // 2)
left = s[0][0::2]
right = s[0][1::2]
rep = []
# 根据点的路径找到对应的边,并输出
for i in range(len(s[0]) // 2):
r = [0] * v_count
r[left[i]] = 1
r[right[i]] = 1
x = [i for i in range(len(m)) if m[i] == r]
rep.append("e" + str(x[0] + 1))
print("M = {", ','.join(rep), '}')
实验测试数据、代码及相关结果分析
-
输入的关联矩阵为
1 0 0 1 1 1 1 0 0 0 0 0 1 1 0 0 1 1 0 1
-
输入的关联矩阵为
1 0 1 1 1 0 1 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 1
-
输入的关联矩阵为
1 0 0 1 0 1 1 1 0 0 0 0 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1
-
输入的关联矩阵为
1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 1
实验代码
Python
import copy
m = []
x = input()
while x:
m.append(list(map(int, x.split())))
x = input()
m = list(map(list, zip(*m)))
# 点的数量
v_count = len(m[0])
# 找到所有点的邻接节点,方便用dfs搜索路径
adpoints = {i: [] for i in range(v_count)}
for each in m:
p = list(filter(lambda x: x[1] == 1, enumerate(each)))
adpoints[p[0][0]].append(p[1][0])
adpoints[p[1][0]].append(p[0][0])
result = []
visited = [False] * v_count
# dfs搜索从start点开始的所有路径
def search(visited, start, re):
vi = copy.deepcopy(visited)
vi[start] = True
r = copy.deepcopy(re)
r.append(start)
flag = True
for i in adpoints[start]:
if not vi[i]:
flag = False
search(vi, i, r)
if flag:
result.append(r)
# 搜索每一个点开始的路径
for i in range(v_count):
search(visited, i, re=[])
# 路径按长度排序
s = sorted(result, key=lambda x: len(x), reverse=True)
print("匹配数=", len(s[0]) // 2)
left = s[0][0::2]
right = s[0][1::2]
rep = []
# 根据点的路径找到对应的边,并输出
for i in range(len(s[0]) // 2):
r = [0] * v_count
r[left[i]] = 1
r[right[i]] = 1
x = [i for i in range(len(m)) if m[i] == r]
rep.append("e" + str(x[0] + 1))
print("M = {", ','.join(rep), '}')
CPP
#include "iostream"
#include "vector"
#include "sstream"
#include "algorithm"
using namespace std;
struct Node {
int num;
vector<Node> child;
};
vector<Node> points;
vector<vector<int>> results;
void search(vector<bool> visited, int left_point, vector<int> rep) {
visited[left_point] = true;
rep.push_back(left_point);
bool flag = true;
for (auto x: points[left_point].child) {
if (!visited[x.num]) {
flag = false;
search(visited, x.num, rep);
}
}
if (flag) {
results.push_back(rep);
}
}
int main() {
cout << "请输入关联矩阵:\n";
string str;
getline(cin, str);
vector<vector<int>> matrix;
int temp;
while (str != "\0") {
stringstream ss(str);
vector<int> t;
for (int j = 1; !ss.eof(); j++) {
ss >> temp;
t.push_back(temp);
}
matrix.push_back(t);
getline(cin, str);
}
unsigned int v_num = matrix.size(), e_num = matrix[0].size();
// 建立节点
for (int i = 0; i < v_num; i++) {
points.push_back(Node{i});
}
for (int j = 0; j < e_num; j++) {
vector<int> t;
for (int i = 0; i < v_num; i++) {
if (matrix[i][j] == 1) t.push_back(i);
}
points[t[0]].child.push_back(points[t[1]]);
points[t[1]].child.push_back(points[t[0]]);
}
vector<bool> visited;
visited.assign(v_num, false);
for (int i = 0; i < v_num; i++) {
search(visited, i, vector<int>());
}
sort(results.begin(), results.end(),
[](const vector<int> &x, const vector<int> &y) { return x.size() > y.size(); });
cout << "匹配数:" << results[0].size() / 2 << endl;
cout << "M = { ";
for (int i = 0; i < (results[0].size() / 2) * 2; i += 2) {
int left = results[0][i], right = results[0][i + 1];
for (int j = 0; j < e_num; j++) {
if (matrix[left][j] == 1 && matrix[right][j] == 1) {
cout << "e" << j + 1 << ",";
break;
}
}
}
cout << "\b }" << endl;
system("pause");
return 0;
}