POJ3041Asteroids【最小点覆盖】

大意:

X.X 
.X. 
.X.
     如左图X代表怪物你可以用激光去消灭它们,一次可以消灭同一行或同一列的所有怪物,问最少多少次才可以把所有怪物消灭完

思路:把x,y坐标分别看成左集合与右集合,若两个坐标有联系就建一条边

最后求得是最小点覆盖

正确性证明:每个怪物的坐标都是由一对x,y确定的,在二分图中每条边就代表一对坐标点,所以只要把所有的边被覆盖就可以了

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <set>
 6 using namespace std;
 7
 8 const int maxn = 505;
 9
10 struct Node {
11     int to, next;
12 }p[10005];
13
14 int head[10005];
15
16 int tot;
17
18 int X[maxn];
19 int x_cnt;
20 int vis[maxn];
21 int link[maxn];
22
23 void AddEdge(int u, int v) {
24     p[tot].to = v;
25     p[tot].next = head[u];
26     head[u] = tot ++;
27 }
28
29 bool Find(int u) {
30     for(int i = head[u]; i; i = p[i].next) {
31         int v = p[i].to;
32         if(!vis[v]) {
33             vis[v] = 1;
34             if(link[v] == -1 || Find(link[v])) {
35                 link[v] = u;
36                 return true;
37             }
38         }
39     }
40     return false;
41 }
42 int n;
43
44 int solve() {
45     int cnt = 0;
46     memset(link, -1, sizeof(link));
47     memset(vis, 0, sizeof(vis));
48     if(Find(X[0])) cnt++;
49     for(int i = 1; i < x_cnt; i++) {
50         if(X[i] == X[i - 1]) continue;
51         memset(vis, 0, sizeof(vis));
52         if(Find(X[i])) cnt++;
53     }
54     return cnt;
55 }
56
57 int main() {
58     int k;
59     int u, v;
60     //freopen("3041.txt","r",stdin);
61     while(EOF != scanf("%d %d",&n, &k)) {
62         tot = 1;
63         x_cnt = 0;
64         memset(head, 0, sizeof(head));
65         //memset(X, 0, sizeof(X));
66         for(int i = 0; i < k; i++) {
67             scanf("%d %d",&u, &v);
68             AddEdge(u, v);
69             X[x_cnt++] = u;
70         }
71         sort(X, X + x_cnt);
72         printf("%d\n",solve());
73     }
74     return 0;
75 }

POJ3041Asteroids【最小点覆盖】,布布扣,bubuko.com

时间: 2024-10-26 13:53:35

POJ3041Asteroids【最小点覆盖】的相关文章

POJ3041Asteroids(最小点覆盖+然而并不是很理解why)

Asteroids Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 18289   Accepted: 9968 Description Bessie wants to navigate her spaceship through a dangerous asteroid field in the shape of an N x N grid (1 <= N <= 500). The grid contains K as

【最小点覆盖】POJ3041-Asteroids

[题目大意] 在n*n的网格上有n个点,每次删除一行或者一列,问至少要删除几次才能删除完全部的这些店? [思路] 在国庆最后一天到来前,把二分图的三个基本情况[最小点覆盖][DAG图的最小路径覆盖]和[二分图的最大独立集]全部复习了一遍. 这道题是非常典型的最小点覆盖,指的是用最少的点让每条边都至少和两个集合中的某一个点关联. 最小点覆盖=二分图最大匹配数. 对于这道题而言,我们把横坐标作为集合X,纵坐标作为集合Y,对于点(x,y),由X中的x连向Y中的y.对于每条边,只要x和y中有一个被删除即

UVA-11419 SAM I AM (最小点覆盖)

题目大意:在一个n*m的网格中,有k个目标,现在可以任选一行或列消除在其上的所有目标,求出最少选择次数及选法. 题目分析:经典的最小点覆盖问题,并且输出一个最小点覆盖集.在求出最大匹配之后,以未覆盖的x点进行标记,沿着未覆盖->覆盖->未覆盖->覆盖...的路径标记,最后x中未标记的和y中标记的点构成最小点覆盖集. 代码如下: # include<iostream> # include<cstdio> # include<cstring> # incl

hdu 1054 Strategic Game 二分图最小点覆盖

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054 题意: 给出一个无向图,求最小点覆盖. 思路: 用网络流来做设立一个超级源点和一个超级汇点. 每个点拆成i和i'. 从超级源点向点i连一条边,容量为1. 从i’向超级汇点连一条边,容量为1. 从i向i'连一条边,容量为正无穷. 然后求最小割/2.因为拆点拆成了2个. 也可以用二分图匹配来做,也是求出最大匹配然后/2. 1 #include <bits/stdc++.h> 2 using na

POJ2226 Muddy Fields(二分图最小点覆盖集)

题目给张R×C的地图,地图上*表示泥地..表示草地,问最少要几块宽1长任意木板才能盖住所有泥地,木板可以重合但不能盖住草地. 把所有行和列连续的泥地(可以放一块木板铺满的)看作点且行和列连续泥地分别作为XY部,每一块泥地看作边.这样就构造出了一个二分图. 那么,问题就是在这个二分图中就是选出最少的点覆盖所有的边,即二分图最小点覆盖集,而二分图最小点覆盖集=二分图最大匹配. 1 #include<cstdio> 2 #include<cstring> 3 #include<qu

UVa11419 SAM I AM(构造最小点覆盖)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27475 [思路] 二分图的最小点覆盖以及构造最小覆盖. 可见:http://www.tuicool.com/articles/jmAnEb [代码] #include<cstdio> #include<cstring> #include<vector> #include<iostream> using namespace st

二分图匹配 + 最小点覆盖 - Vertex Cover

Vertex Cover Problem's Link Mean: 给你一个无向图,让你给图中的结点染色,使得:每条边的两个顶点至少有一个顶点被染色.求最少的染色顶点数. analyse: 裸的最小点覆盖问题,二分图的最大匹配,直接套模版即可. Time complexity: O(N^2) view code

hdu 1151 或 poj 1422 二分图 最小点覆盖集

最小点覆盖集的裸题,只要“拆点建边”然后求出最大匹配,则:最小点覆盖集的大小 = 点数 - 最大匹配 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 121; 7 const int M = 5000; 8 bool visit[N]; 9 int mark[N]; 10 int head[N]; 11 int

POJ3041 Asteroids【二分图最小点覆盖】

题目链接: http://poj.org/problem?id=3041 题目大意: 有一个N*N的矩阵,有些格子上有障碍物(坐标为(x,y) ),在消除这些障碍物的时候,可以一次性消除 该障碍物同一行所有的障碍物,或是一次性消除该障碍物同一列所有的障碍物.只能选择清理该行或是 清理该列.问:最小进行多少次消除,就可以清理所有的障碍物. 思路: 可以将每一行当做一个点,这样总共有N个点,作为二分图的一边.将每一列当做一个点,这样又有N 个点,作为二分图的另一边.将有障碍物的行点和列点连接起来,每