poj3020 Antenna Placement(无向图最小边覆盖)

本文介绍了一道经典的无向图最小边覆盖问题,并通过一个具体的编程实例详细讲解了解决方案。利用二分匹配原理,文章展示了如何为给定的城市布局找到最少数量的无线网络覆盖方案。

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


http://poj.org/problem?id=3020

题意:给你一个n*m的图,'*'表示城市,每个无线网只能覆盖两个城市,且这两个城市只能东南西北相邻,求最小用多少这样的无线网可以覆盖所有的城市。


ps:做完这道题我感觉英语不好这题就做不出来。。


思路:无向图的最小边覆盖。刚开始各种看不懂题我就不说了= =。一开始一看是矩阵以为和上一道题一样,结果感觉这才是真正的二分匹配变形。二分匹配还可以这么玩!把每个城市编号,无向图的最小边覆盖相当于最大匹配数+相对孤立节点数。不过顶点数减去这个最小边覆盖依然等于最大匹配数(匹配是两两成对的),所以还是求最小边覆盖嘛!(感觉绕了个弯。。)这个还加了点搜索的思想,加点条件就行,四个方向每发现一个点就建立当前点到目的点的单向边,这样边就不会算漏。因为是无向图,匹配数记得除二哈。好在数据不是很大,1A,哦也~


#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <queue>
#include <stack>
#include <ctype.h>

using namespace std;

typedef long long LL;

const int N = 505;
const int INF = 0x3f3f3f3f;

int head[N], match[N];
bool vis[N];
int cnt;

struct Edge
{
    int to,next;
}edge[N*N];

void add(int u, int v)
{
    edge[cnt] = (struct Edge){v, head[u]};
    head[u] = cnt++;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}

bool Augment(int u)
{
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if(!vis[v])
        {
            vis[v] = true;
            if(match[v]==-1 || Augment(match[v]))
            {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}

int Hungary(int num)
{
    int ans = 0;
    memset(match, -1, sizeof(match));
    for(int i = 1; i <= num; i++)
    {
        memset(vis, false, sizeof(vis));
        if(Augment(i)) ans++;
    }
    return ans;
}

int main()
{
   // freopen("in.txt", "r", stdin);
    int t, n, u, v, m;
    int G[N][N];
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        init();
        char x;
        int num = 1;
        memset(G, -1, sizeof(G));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                cin >> x;
                if(x == 'o') G[i][j] = 0;
                else if(x == '*')
                {
                    G[i][j] = num;
                    num++;
                }
            }
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                if(G[i-1][j] >= 1) add(G[i][j], G[i-1][j]);
                if(G[i+1][j] >= 1) add(G[i][j], G[i+1][j]);
                if(G[i][j-1] >= 1) add(G[i][j], G[i][j-1]);
                if(G[i][j+1] >= 1) add(G[i][j], G[i][j+1]);
            }
        num--;
        printf("%d\n", num-Hungary(num)/2);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值