Antenna Placement (二分图匹配)

本文探讨了一种名为4DAir的新型基站部署问题,旨在通过合理布局最少数量的基站来实现对所有指定兴趣点的有效覆盖。文章介绍了一个具体算法案例,通过匈牙利算法求解最小覆盖路径问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Antenna Placement

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

大意就是:就是说给你一张图,用‘*‘来表示城市,然后城市要覆盖4G什么东西,每个城市覆盖上之后可以向上下左
右四个方向延伸,可以多覆盖一个,然后让我们求一个最小的基站数,其实就是求最小路径覆盖率。

最小路径覆盖数= 顶点数 - 最大匹配数,最大匹配直接用匈牙利算法就可以求出了,这道题就是会建图就会做了,因为是无向图,所以最大匹配要除于2。

我们来看一下样例2的建图:

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define INF 0x3f3f3f

const int maxn=505;

int nx,ny;//x集合和y集合中顶点的个数
int edge[maxn][maxn];//edge[i][j]为1表示ij可以匹配
int cx[maxn],cy[maxn];//用来记录x集合中匹配的y元素是哪个!
int visited[maxn];//用来记录该顶点是否被访问过!
char s[maxn][maxn];
int b[maxn][maxn];
int h,w;
int n,m;
int path(int u)
{
    int v;
    for(v=1; v<=m; v++)
    {
        if(edge[u][v]&&!visited[v])
        {
            visited[v]=1;
            if(cy[v]==-1||path(cy[v]))
            {
                cy[v]=u;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&h,&w);
        int ans=1;
        memset(b,0,sizeof(b));
        for(int i=1; i<=h; i++)
        {
            for(int j=1; j<=w; j++)
            {
                scanf(" %c",&s[i][j]);
                if(s[i][j]=='*')
                    b[i][j]=ans++;
            }
        }
        n=m=ans;
        memset(edge,0,sizeof(edge));
        for(int i=1; i<=h; i++)
        {
            for(int j=1; j<=w; j++)
            {
                if(s[i][j]=='*')
                {
                    if(i > 1 && s[i-1][j] == '*')
                        edge[b[i-1][j]][b[i][j]] = 1;
                    if(i < h && s[i+1][j] == '*')
                        edge[b[i+1][j]][b[i][j]] = 1;
                    if(j > 1 && s[i][j-1] == '*')
                        edge[b[i][j-1]][b[i][j]] = 1;
                    if(j < w && s[i][j+1] == '*')
                        edge[b[i][j+1]][b[i][j]] = 1;
                }
            }
        }
        int res=0;
        memset(cy,0xff,sizeof(cy));
        for(int i=1; i<=n; i++)
        {
            memset(visited,0,sizeof(visited));
            res+=path(i);
        }
        //printf("%d\n",res);
        printf("%d\n",ans-1-res/2);
    }
    return 0;
}

其实建好图就基本可以套模板了。

匈牙利算法的dfs版本模板:


#define maxn 10//表示x集合和y集合中顶点的最大个数!  
  int nx,ny;//x集合和y集合中顶点的个数  
  int edge[maxn][maxn];//edge[i][j]为1表示ij可以匹配  
  int cx[maxn],cy[maxn];//用来记录x集合中匹配的y元素是哪个!  
  int visited[maxn];//用来记录该顶点是否被访问过!  
  int path(int u)  
  {  
      int v;  
      for(v=0;v<ny;v++)  
      {  
          if(edge[u][v]&&!visited[v])  
          {  
              visited[v]=1;  
             if(cy[v]==-1||path(cy[v]))//如果y集合中的v元素没有匹配或者是v已经匹配,但是从cy[v]中能够找到一条增广路  
              {  
                  cx[u]=v; //找到增广路,修改匹配M  
                  cy[v]=u;  
                  return 1;  
              }  
          }  
      }  
      return 0;  
  }  
  int maxmatch()  
  {  
      int res=0;  
      memset(cx,0xff,sizeof(cx));//初始值为-1表示两个集合中都没有匹配的元素!  
      memset(cy,0xff,sizeof(cy));  
      for(int i=0;i<=nx;i++)  
      {  
          if(cx[i]==-1)   //还没被匹配,执行内部代码  
          {  
              memset(visited,0,sizeof(visitited));  //重置标记为为访问  
              res+=path(i);   //以 i 为起点开始查找增广路,返回true ,匹配数+1  
          }  
      }  
      return res;  
  }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值