标签:
想理解的更透彻,可以看这里。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;
const int N = 1005;
typedef long long ll;
int n, m, k;
vector<int> X, Y;
void init() {
X.clear();
Y.clear();
}
struct BPM{
int n, m;
vector<int > G[N];
int left[N];
int right[N];
bool T[N];
bool S[N];
void init(int n,int m){
this->n = n;
this->m = m;
for(int i = 0; i < N; i++) G[i].clear();
}
void addEdge(int u, int v){
G[u].push_back(v); //建边
}
bool match(int u) {
S[u] = true; //标记右边的点u
for(int i = 0; i < G[u].size(); i++){ //遍历由u点出发,连接的左边的点
int v = G[u][i];
if(!T[v]){ //左边的没标记过的点, 走没匹配过的边
T[v] = true;
if(left[v] == -1 || match(left[v])){ //走匹配过的边到右边的点
left[v] = u;
right[u] = v;
return true;
}
}
}
return false;
}
int solve(){
memset(left, -1, sizeof(left));
memset(right, -1, sizeof(right));
int ans = 0;
for(int u = 0; u < n; u++){
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
if(match(u)) ans++; //先用匈牙利算法求出最大匹配
}
return ans;
}
int mincover(vector<int>& X, vector<int>& Y){
int ans = solve();
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
for(int u = 0; u < n; u++) //在右边的点集找到一个未被标记的点
if(right[u] == -1) match(u); //从这个未标记的点开始走增广路
for(int u = 0; u < n; u++)
if(!S[u]) X.push_back(u); //标记结束之后,记录右边没标记的点
for(int v = 0; v < n; v++)
if(T[v]) Y.push_back(v); //记录左边标记过的点
return ans;
}
}bpm;
void input() {
int x, y;
for (int i = 0; i < k; i++) {
scanf("%d %d", &x, &y);
x--, y--;
bpm.addEdge(x, y);
}
}
int main() {
while (scanf("%d %d %d", &n, &m, &k) == 3) {
if (!n && !m && !k) break;
bpm.init(n, m);
init();
input();
printf("%d", bpm.mincover(X, Y));
for (int i = 0; i < X.size(); i++) printf(" r%d", X[i] + 1);
for (int i = 0; i < Y.size(); i++) printf(" c%d", Y[i] + 1);
puts("");
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不可转载。
uva 11419 SAM I AM (最小覆盖 König定理)
标签:
原文地址:http://blog.csdn.net/llx523113241/article/details/47759745