首页 > 代码库 > POJ3041Asteroids【最小点覆盖】
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 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。