poj3041 二分图最小点覆盖

本文介绍了一种使用二分图最大匹配算法解决两类问题的方法:一是通过射击行或列清除障碍;二是利用木板覆盖泥泞区域,旨在寻找最少的行动次数或物品数量。

Asteroids
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 16247 Accepted: 8837

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 4
1 1
1 3
2 2
3 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).

行看成X部,列看成Y部,若(Xi,Yi)有小行星,那么就在Xi和Yi之间连一条线,这样我们只要求一个最小点覆盖即可,因为每覆盖一条边,就相当于炸掉一颗小行星。二分图最小点覆盖=最大匹配。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 510
using namespace std;

int adj[Maxn][Maxn];
int match[Maxn];
int vis[Maxn];
int x,y;
int deep;
bool dfs(int u){
    for(int v=1;v<=y;v++){
        if(adj[u][v]&&vis[v]!=deep){
            vis[v]=deep;
            if(match[v]==-1||dfs(match[v])){
                match[v]=u;
                return true;
            }
        }
    }
    return false;
}
int hungary(){
    memset(match,-1,sizeof match);
    memset(vis,-1,sizeof vis);
    int ans=0;
    for(int i=1;i<=x;i++){
        deep=i;
        if(dfs(i)) ans++;
    }
    return ans;
}
int main()
{
    int n,m,a,b;
    while(cin>>n>>m){
        x=y=n;
        for(int i=0;i<m;i++){
            cin>>a>>b;
            adj[a][b]=1;
        }
        printf("%d\n",hungary());
    }
	return 0;
}


poj2226:这题和上面建图不同,思想类似。此题不是按行和列来建图的,是按照每行连续的块和每列连续的块来建图。

Muddy Fields
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8615 Accepted: 3181

Description

Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <= 50). While good for the grass, the rain makes some patches of bare earth quite muddy. The cows, being meticulous grazers, don't want to get their hooves dirty while they eat. 

To prevent those muddy hooves, Farmer John will place a number of wooden boards over the muddy parts of the cows' field. Each of the boards is 1 unit wide, and can be any length long. Each board must be aligned parallel to one of the sides of the field. 

Farmer John wishes to minimize the number of boards needed to cover the muddy spots, some of which might require more than one board to cover. The boards may not cover any grass and deprive the cows of grazing area but they can overlap each other. 

Compute the minimum number of boards FJ requires to cover all the mud in the field.

Input

* Line 1: Two space-separated integers: R and C 

* Lines 2..R+1: Each line contains a string of C characters, with '*' representing a muddy patch, and '.' representing a grassy patch. No spaces are present.

Output

* Line 1: A single integer representing the number of boards FJ needs.

Sample Input

4 4
*.*.
.***
***.
..*.

Sample Output

4

Hint

OUTPUT DETAILS: 

Boards 1, 2, 3 and 4 are placed as follows: 
1.2. 
.333 
444. 
..2. 
Board 2 overlaps boards 3 and 4.

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 1260
using namespace std;

int adj[Maxn][Maxn];
int match[Maxn];
int vis[Maxn];
int x,y;
int deep;
bool dfs(int u){
    for(int v=1;v<=y;v++){
        if(adj[u][v]&&vis[v]!=deep){
            vis[v]=deep;
            if(match[v]==-1||dfs(match[v])){
                match[v]=u;
                return true;
            }
        }
    }
    return false;
}
int hungary(){
    memset(match,-1,sizeof match);
    memset(vis,-1,sizeof vis);
    int ans=0;
    for(int i=1;i<=x;i++){
        deep=i;
        if(dfs(i)) ans++;
    }
    return ans;
}
char s[60][60];
int r[60][60],c[60][60];
int main()
{
    int n,m;
    while(cin>>n>>m){
        for(int i=0;i<n;i++)
            scanf("%s",s[i]);
        int tot=0;
        for(int i=0;i<n;i++){
            bool flag=false;
            for(int j=0;j<m;j++)
                if(s[i][j]=='*'){
                    if(!flag) {r[i][j]=++tot;flag=true;}
                    else r[i][j]=tot;
                }
                else flag=false;
        }
        x=tot;
        tot=0;
        for(int j=0;j<m;j++){
            bool flag=false;
            for(int i=0;i<n;i++)
                if(s[i][j]=='*'){
                    if(!flag) {c[i][j]=++tot;flag=true;}
                    else c[i][j]=tot;
                }
                else flag=false;
        }
        y=tot;
        memset(adj,0,sizeof adj);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                if(s[i][j]=='*') adj[r[i][j]][c[i][j]]=1;
        printf("%d\n",hungary());
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值