poj 3401
题意:给定一个n*n的矩阵,其中分布着m个东西吧,每一次行操作或者列操作都可以消除整行或整列,求最小的操作次数
分析:以行和列建立左右顶集, 因此为一个二分图,对于i, j位置有一个东西这建立一条这样的边, 表示行i或列j至少要进行一次操作,也就是选出最少的边,使得每一个顶点至少被一条边覆盖, 这个就是最小点覆盖,二分图中这个等于最大匹配
#include
#include
#include
#include
const int N = 500 + 5;
int n, m;
int match[N], vis[N];
std::vector edges[N];
bool dfs(int u) {
for (int i = 0; i < (int)edges[u].size(); i ++) {
int v = edges[u][i];
if (!vis[v]) {
vis[v] = true;
if (match[v] == -1 || dfs(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
}
int hungary() {
int ret = 0;
std::fill(match, match + n, -1);
for (int i = 0; i < n; i ++) {
std::fill(vis, vis + n, false);
if (dfs(i)) {
ret ++;
}
}
return ret;
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
std::fill(edges, edges + n, std::vector ());
for (int i = 0; i < m; i ++) {
int u, v;
scanf("%d%d", &u, &v);
u --, v --;
edges[u].push_back(v);
}
printf("%d\n", hungary());
}
return 0;
}
Regionals 2014 :: Asia - Taichung I题
题意:平面上有N个点,一次行操作可以消除角度相同的所有点,一次圆操作可以消除圆上的点,问最小的操作次数
分析:做法同上, 建图时可以用不同的角度和不同的距离建图, 这样就是二分图
#include
const int N = 20000 + 5;
int n;
int vis[N], match[N];
int d[N], x[N], y[N];
std::vector circle;
std::vector line;
std::vector edges[N];
bool dfs(int u) {
for (int i = 0; i < (int)edges[u].size(); i ++) {
int v = edges[u][i];
if (!vis[v]) {
vis[v] = true;
if (match[v] == -1 || dfs(match[v])) {
match[v] = u;
return true;
}
}
}
return false;
}
int work() {
std::sort(line.begin(), line.end());
std::sort(circle.begin(), circle.end());
line.erase(std::unique(line.begin(), line.end()), line.end());
circle.erase(std::unique(circle.begin(), circle.end()), circle.end());
int row = (int)line.size();
int col = (int)circle.size();
std::fill(edges, edges + row, std::vector ());
for (int i = 0; i < n; i ++) {
int a = std::lower_bound(line.begin(), line.end(), 1.0 * y[i] / x[i]) -
line.begin();
int b = std::lower_bound(circle.begin(), circle.end(), d[i]) -
circle.begin();
edges[a].push_back(b);
}
int ret = 0;
memset(match, -1, sizeof(match[00]) * col);
for (int i = 0; i < row; i ++) {
memset(vis, false, sizeof(vis[0]) * col);
if (dfs(i)) {
ret ++;
}
}
return ret;
}
int main() {
int t;
scanf("%d", &t);
while (t --) {
scanf("%d", &n);
circle.clear();
line.clear();
for (int i = 0; i < n; i ++) {
scanf("%d%d%d", &d[i], &x[i], &y[i]);
circle.push_back(d[i]);
line.push_back(1.0 * y[i] / x[i]);
}
printf("%d\n", work());
}
return 0;
}
// 匈牙利算法的复杂度:O(E * sqrt(V));