二分图最大匹配
题意:
分析:
经典的求最大子集的问题。我们先求最大匹配。最大子集 = 总定点数 - 最大匹配
选择你的算法,我选择HK算法!
但是摆在我们面前的还有一个问题:如何区分图中顶点所在的集合?
1.染色法:
我们连完边建完图后,进行搜索,搜索深度为奇数的为一个子集,为偶数的为一个子集
2.观察法:
对,我们不妨先在草稿纸上画画:
这是我画的,我们很容易就发现当i+j为奇数是是一个子集,为偶数时是另一个子集。
如此我们找到了划分的一句。接下来划分就可以了。
代码如下:
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
pair<int, int> pii;
const int max_n = 330;
int n;
const int inf = 2e9;
char M[max_n][max_n];
int map[max_n][max_n];
vector<int> G[max_n * max_n];
int dir[8][2] = { {-2,-1},{-2,1},{-1,-2},{-1,2},{1,2},{1,-2},{2,1},{2,-1} };
int rightTo[max_n * max_n];
int leftTo[max_n * max_n];
int distright[max_n * max_n];
int distleft[max_n * max_n];
int dist;
int tot1, tot2;
bool searchpath() {
fill(distright, distright + tot1 + 1, -1);
fill(distleft, distleft + 1 + tot2, -1);
queue<int> que;dist = inf;
for (int i = 1;i <= tot1;i++) {
if (rightTo[i] == -1) {
que.push(i);
distright[i] = 0;
}
}
while (!que.empty()) {
int u = que.front();que.pop();
if (distright[u] > dist)break;
for (int i = 0;i < G[u].size();i++) {
int v = G[u][i];
if (distleft[v] != -1)continue;
distleft[v] = distright[u] + 1;
if (leftTo[v] == -1)dist = distleft[v];
else {
distright[leftTo[v]] = distleft[v] + 1;
que.push(leftTo[v]);
}
}
}return dist != inf;
}
bool matchpath(int x) {
for (int i = 0;i < G[x].size();i++) {
int v = G[x][i];
if (distleft[v] != distright[x] + 1)continue;
if (distleft[v] == dist && leftTo[v] != -1)continue;
distleft[v] = -1;
if (leftTo[v] == -1 || matchpath(leftTo[v])) {
leftTo[v] = x;rightTo[x] = v;
return true;
}
}return false;
}
int HK() {
fill(rightTo, rightTo + tot1 + 1, -1);
fill(leftTo, leftTo + tot2 + 1, -1);
int ans = 0;
while (searchpath()) {
for (int i = 1;i <= tot1;i++) {
if (rightTo[i] == -1 && matchpath(i))
ans++;
}
}return ans;
}
int main() {
ios::sync_with_stdio(0);
cin >> n;
for (int i = 1;i <= n;i++)
for (int j = 1;j <= n;j++)
cin >> M[i][j];
tot1 = tot2 = 0;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
if (M[i][j] == '1')continue;
if (i + j & 1)map[i][j] = ++tot2;
else map[i][j] = ++tot1;
}
}
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) {
if (M[i][j] == '1')continue;
if (!((i + j) & 1)) {
for (int k = 0;k < 8;k++) {
int x = i + dir[k][0];
int y = j + dir[k][1];
if (x<1 || y<1 || x>n || y>n || M[x][y] == '1')continue;
G[map[i][j]].push_back(map[x][y]);
}
}
}
}
cout << tot1 + tot2 - HK() << endl;
}
京公网安备 11010502036488号