当前位置:   article > 正文

POJ 3041 Asteroids (最小顶点覆盖)_最小顶点覆盖 贪心反例

最小顶点覆盖 贪心反例
题目类型  最小顶点覆盖

题目意思
给出最多10000个点的坐标 每次可以消除同一行的点或同一列的点 问至少要多少次才能把所有点都消除掉

解题方法
首先建图 每一个行号为一个点 每一个列号为一个点 那么对于一个要消除的点就对应一条这个点的行号与这个点的列号相连的边
那么消除所有点的目的就转化成对于每条边都要从这条边的两个端点找一个点与这条边关联, 即求最少的点让每条边都至少和其中的一个点关联
这就是最小顶点覆盖问题 可以证明 最小顶点覆盖数 = 最大匹配数M,  求最大匹配可以使用匈牙利算法

证明如下(黑书p332):
(1) M个是足够的。只需要让它们覆盖最大匹配的M条边,则其它边一定被覆盖 (如果有边e不被覆盖, 把e加入后得到一个更大的匹配)
(2) M个是必需的。仅考虑形成最大匹配边的这M条边, 由于它们两两无公共点, 因此至少需要M个点才能把它们覆盖

参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <vector>
  5. using namespace std;
  6. const int maxn = 500 + 10;
  7. vector<int>E[maxn];
  8. bool vis[maxn];
  9. int y[maxn];
  10. bool dfs(int u) {
  11. for( int i=0; i<E[u].size(); i++ ) {
  12. int v = E[u][i];
  13. if(vis[v]) continue;
  14. vis[v] = true;
  15. if(y[v] == 0 || dfs(y[v])) {
  16. //printf("u = %d v = %d y[v] = %d\n", u, v, y[v]);
  17. y[v] = u;
  18. return true;
  19. }
  20. }
  21. return false;
  22. }
  23. int main() {
  24. freopen("in", "r", stdin);
  25. int n, m;
  26. while(scanf("%d%d", &n, &m) != EOF) {
  27. for( int i=1; i<=n; i++ ) E[i].clear();
  28. for( int i=0; i<m; i++ ) {
  29. int u, v;
  30. scanf("%d%d", &u, &v);
  31. E[u].push_back(v);
  32. }
  33. int ans = 0;
  34. memset(y, 0, sizeof(y));
  35. for( int i=1; i<=n; i++ ) {
  36. memset(vis, 0, sizeof(vis));
  37. if(dfs(i)) ans++;
  38. }
  39. printf("%d\n", ans);
  40. }
  41. return 0;
  42. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/856725
推荐阅读
相关标签
  

闽ICP备14008679号