poj 3020 二分图 最大匹配(最小边覆盖问题)

Antenna Placement
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 5774 Accepted: 2884

Description

The Global Aerial Research Centre has been allotted the task of building the fifth generation of mobile phone nets in Sweden. The most striking reason why they got the job, is their discovery of a new, highly noise resistant, antenna. It is called 4DAir, and comes in four types. Each type can only transmit and receive signals in a direction aligned with a (slightly skewed) latitudinal and longitudinal grid, because of the interacting electromagnetic field of the earth. The four types correspond to antennas operating in the directions north, west, south, and east, respectively. Below is an example picture of places of interest, depicted by twelve small rings, and nine 4DAir antennas depicted by ellipses covering them.

Obviously, it is desirable to use as few antennas as possible, but still provide coverage for each place of interest. We model the problem as follows: Let A be a rectangular matrix describing the surface of Sweden, where an entry of A either is a point of interest, which must be covered by at least one antenna, or empty space. Antennas can only be positioned at an entry in A. When an antenna is placed at row r and column c, this entry is considered covered, but also one of the neighbouring entries (c+1,r),(c,r+1),(c-1,r), or (c,r-1), is covered depending on the type chosen for this particular antenna. What is the least number of antennas for which there exists a placement in A such that all points of interest are covered?

Input

On the first row of input is a single positive integer n, specifying the number of scenarios that follow. Each scenario begins with a row containing two positive integers h and w, with 1 <= h <= 40 and 0 < w <= 10. Thereafter is a matrix presented, describing the points of interest in Sweden in the form of h lines, each containing w characters from the set ['*','o']. A '*'-character symbolises a point of interest, whereas a 'o'-character represents open space.

Output

For each scenario, output the minimum number of antennas necessary to cover all '*'-entries in the scenario's matrix, on a row of its own.

Sample Input

2
7 9
ooo**oooo
**oo*ooo*
o*oo**o**
ooooooooo
*******oo
o*o*oo*oo
*******oo
10 1
*
*
*
o
*
*
*
*
*
*

Sample Output

17
5

Source

Svenskt Mästerskap i Programmering/Norgesmesterskapet 2001



该题用到的重要定理是:
|最大匹配| + |最小边覆盖| = V
|最小顶点覆盖| + |最大独立集|   = V


而|最大匹配| = |最小顶点覆盖|
独立集的定义:G中两两互不相连的顶点集合。
由此可见,二分图中的问题都可以转化为求最大匹配的问题,用匈牙利算法求解。难处就在于如何建图。

可以看出该题需要求最小边覆盖(即最少画多少条边可以把所有的点都覆盖到)。
想转化为二分图,则采用一种 拆点的技术,即一个点拆为2个点。
比如1-2 2-3 则可以拆为
1-2'
1'-2
2-3'
2'-3
这四个点。
这样这个新图就成了一个二分图。

用上面的 V - |最大匹配数| 就可以求出最小边覆盖。
最后再除以2.

#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#include 
        
        
          #include 
         
           #include 
          
            #define oo 1000000 #define MAXV 500 * 2 using namespace std; int V, m; vector 
           
             G[MAXV]; int match[MAXV]; bool used[MAXV]; void add_edge(int u, int v) { G[u].push_back(v); G[v].push_back(u); } bool dfs(int v) { 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; int v; for (v = 0; v <= V; v++) match[v] = -1;//这两句修改为0-V。因为模板多一个结点实际上是没关系的。如果这个结点没有边相连,那也不会处理它 for (v = 0; v <= V; v++) { if (match[v] < 0) { memset(used, 0, sizeof(used)); if (dfs(v)) res++; } } return res; } int main() { int t; int i, j; cin >> t; char map[50][50]; int nodenum[50][50]; while (t--) { int h, w; cin >> h >> w; for (i = 0; i < MAXV; i++) G[i].clear(); int num = 0; for (i = 1; i <= h; i++) { for (j = 1; j <= w; j++) { cin >> map[i][j]; if (map[i][j] == '*') nodenum[i][j] = ++num; } } for (i = 1; i <= h; i++) { for (j = 1; j <= w; j++) { if (map[i][j] == '*' && j < w && map[i][j+1] == '*') { add_edge(nodenum[i][j], num + nodenum[i][j+1]); add_edge(num + nodenum[i][j], nodenum[i][j+1]); } if (map[i][j] == '*' && i < h && map[i+1][j] == '*') { add_edge(nodenum[i][j], num + nodenum[i+1][j]); add_edge(num + nodenum[i][j], nodenum[i+1][j]); } } } V = num * 2;//总坐标乘以2 cout << (V - bipartite_matching()) / 2 << endl;//二分图的最大匹配数等于二分图的最大点集覆盖数 } return 0; } 
            
           
          
        
       
       
      
      
     
     
    
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值