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));