POJ 3041-Asteroids(二分圖匹配)

kewlgrl發表於2016-07-26
Asteroids
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 20099   Accepted: 10900

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).

Source


題目意思:

N*N的網格中有K顆小行星,小行星i的位置是(Ri,Ci)。現在有一個強力武器能夠一發光束將一行或者是一列的小行星轟為灰燼。現在想要利用這個武器摧毀所有的小行星,至少需要多少發光束?

解題思路:

轉換為圖:把每一行和列都當做一個點,若行列之間有邊連線起來就說明這個行列之間有小行星。
光束的攻擊方案對應一個頂點集S,而要求攻擊的方案能摧毀所有的小行星就是說,圖中的每條邊都至少有一個屬於S的頂點。
這樣一來,轉換成最小頂點匹配問題。

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
#define MAXN 5000
using namespace std;

int V,N,K;//二分圖頂點數、網格行列數、小行星數
int R[MAXN],C[MAXN];
vector<int>G[MAXN];//圖的鄰接表表示
int match[MAXN];//所匹配的頂點
bool used[MAXN];//DFS訪問標記

void add_edge(int u,int v)//向圖中增加一條連線u和v的邊
{
    G[u].push_back(v);
    G[v].push_back(u);
}

bool dfs(int v)//dfs尋找增廣路
{
    used[v]=true;
    for(int i=0; i<G[v].size(); ++i)
    {
        int u=G[v][i],w=match[u];
        if(w<0||!used[w]&&dfs(w))
        {
            match[v]=u;
            match[u]=v;
            return true;
        }
    }
    return false;
}

int bipartite_matching()//二分圖最大匹配
{
    int res=0;
    memset(match,-1,sizeof(match));
    for(int v=0; v<V; ++v)
        if(match[v]<0)
        {
            memset(used,0,sizeof(used));
            if(dfs(v)) ++res;
        }
    return res;
}

void solve()
{
    V=2*N;
    for(int i=0; i<K; ++i)
        add_edge(R[i]-1,N+C[i]-1);
    cout<<bipartite_matching()<<endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>N>>K;
    for(int i=0; i<K; ++i)
        cin>>R[i]>>C[i];
    solve();
    return 0;
}


相關文章