解题报告 之 POJ3041 Asteroids

来源:互联网 发布:大数据自学 编辑:程序博客网 时间:2024/05/02 04:46

解题报告 之 POJ3041 Asteroids


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 asteroids (1 <= K <= 10,000), which are conveniently located at the lattice points of the grid. 

Fortunately, Bessie has a powerful weapon that can vaporize all the asteroids in any given row or column of the grid with a single shot.This weapon is quite expensive, so she wishes to use it sparingly.Given the location of all the asteroids in the field, find the minimum number of shots Bessie needs to fire to eliminate all of the asteroids.

Input

* Line 1: Two integers N and K, separated by a single space. 
* Lines 2..K+1: Each line contains two space-separated integers R and C (1 <= R, C <= N) denoting the row and column coordinates of an asteroid, respectively.

Output

* Line 1: The integer representing the minimum number of times Bessie must shoot.

Sample Input

3 41 11 32 23 2

Sample Output

2

Hint

INPUT DETAILS: 
The following diagram represents the data, where "X" is an asteroid and "." is empty space: 
X.X 
.X. 
.X.


OUTPUT DETAILS: 
Bessie may fire across row 1 to destroy the asteroids at (1,1) and (1,3), and then she may fire down column 2 to destroy the asteroids at (2,2) and (3,2).


题目大意:一个n*n的地图上有k个陨石,告诉你他们的坐标,你的激光武器可以一次破坏一排或者一列的陨石,问你至少要使用多少条激光才能消灭所有陨石。

分析:我们采用最大流来解决该问题。首先有一个技巧,比较反常规,就是将每一行和每一列作为节点,而陨石为边。为什么呢?某行和某列如果存在一条边,那么说明该行该列的交点处有一个陨石需要消灭。效果如下:
 
        
                                         图1                                                                            图2     


从图1中可以看出本题需要两条激光,然后我们按照上述的建图方法建为图2。
那么我们可以看出,我们需要从{r1,r2,r3,c1,c2,c3}中找 到一个子集,使得所有边都与这个子集中的点相连。
所以将题目转化为最小点覆盖的问题。根据结论,二分图的最小点覆盖 = 二分图最大匹配。
于是最后再跑一个最大流即可。

上代码:
#include<iostream>#include<cstring>#include<algorithm>#include<queue>#include<cstdio>using namespace std;const int MAXN = 1210;const int MAXM = 21000;const int INF = 0x3f3f3f3f;struct Edge{int from, to, cap, next;};Edge edge[MAXM];int level[MAXN];int head[MAXN];int src, des, cnt;void addedge(int from,int to,int cap){edge[cnt].from = from;edge[cnt].to = to;edge[cnt].cap = cap;edge[cnt].next = head[from];head[from] = cnt++;swap( from, to );edge[cnt].from = from;edge[cnt].to = to;edge[cnt].cap = 0;edge[cnt].next = head[from];head[from] = cnt++;}int bfs(){memset( level, -1, sizeof level );queue<int> q;while(!q.empty())q.pop();level[src] = 0;q.push( src );while(!q.empty()){int u = q.front();q.pop();for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if(edge[i].cap&&level[v] == -1){level[v] = level[u] + 1;q.push( v );}}}return level[des] != -1;}int dfs( int u, int f ){if(u == des)return f;int tem;for(int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if(edge[i].cap > 0 && level[v] == level[u] + 1){tem = dfs( v, min( f, edge[i].cap ) );if(tem > 0){edge[i].cap -= tem;edge[i^1].cap += tem;return tem;}}}level[u] = -1;return 0;}int Dinic(){int ans = 0, tem;while(bfs()){while((tem = dfs( src, INF ) > 0)){ans += tem;}}return ans;}int main(){int n, k;src = 0; des = 1205;while(cin >> n >> k){memset( head, -1, sizeof head );cnt = 0;for(int i = 1; i <= n; i++){addedge( src, i, 1 );addedge( i + 500, des, 1 );}for(int i = 1; i <= k; i++){int a, b;cin >> a >> b;addedge( a, b + 500, 1 );}cout << Dinic() << endl;}return 0;}

所以这题的总结就是巧妙的建图思路加上最小点覆盖转化为二分图最大匹配。
1 0