题目传送门:【POJ 3041】
题目大意:贝茜想驾驶她的飞船穿过危险的小行星群。小行星群是一个 N * N 的网格 (1 ≤ N ≤ 500),在网格内有 K 个小行星 ( 1 ≤ K ≤ 10000)。幸运地是贝茜有一个很强大的武器,一次可以消除所有在一行或一列中的小行星。这种武器很贵,所以她希望尽量地少用。给出所有的小行星的位置,算出贝茜最少需要多少次射击就能消除所有的小行星。
输入第一行为 N 和 K,之后的 K 行,每行两个整数 R,C,代表一个小行星的位置。输出为一个整数,代表使用武器的最少次数。
题目分析:
这道题是我拿来当模板练手的。
由题,由于每次我们可以消除整行或整列的小行星,根据题目性质,所以我们可以将其转化为二分图,求出其最小点覆盖即可。又因为最小点覆盖等于最大匹配,所以直接跑一次关于二分图最大匹配的算法即可。
下面附上代码:
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- const int MXN = 505,MXK = 10005;
- struct Edge{
- int to,next;
- };
- Edge edge[MXK * 2];
- int maps[MXN][MXN];
- int head[MXK],now = 0,match[MXN * 2],n,k,ans = 0;
- bool vis[MXN * 2];
- void adde(int u,int v){
- edge[++now].to = v;
- edge[now].next = head[u];
- head[u] = now;
- }
- bool hungary(int u){ //最小点覆盖 = 最大匹配
- for (int i = head[u];i;i = edge[i].next){
- int v = edge[i].to;
- if (!vis[v]){
- vis[v] = true;
- if (match[v] == 0 || hungary(match[v])){
- match[v] = u;
- return true;
- }
- }
- }
- return false;
- }
- int main(){
- int T,a,b;
- cin>>n>>k;
- for (int i = 1;i <= k;i++){
- scanf(”%d%d”,&a,&b);
- adde(a,b + 500);
- adde(b + 500,a);
- }
- for (int i = 1;i <= n;i++){
- memset(vis,0,sizeof(vis));
- if (hungary(i)) ++ans;
- }
- cout<<ans<<endl;
- return 0;
- }