POJ - 3020 ? Antenna Placement 二分图最大匹配

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

首先注意到,答案的最大值是‘*‘的个数,也就是相当于我每用一次那个技能,我只套一个‘*‘,是等价的。

所以,每结合一对**,则可以减少一次使用,所以就是找**的最大匹配数目。

对于每一个*,和它的上下左右连接一条边(如果是*才连)

那么,这个图是一个二分图,怎么找到左边集合S,右边集合T呢?

我的做法是染色一次,就可以。

这题应该不能贪心吧。

3 5

*****

o***o

o*o*o

其实也可以不分开S、T

跑一发最大匹配,然后匹配数 / 2即可。意思就是match[1] = 2,也可以match[2] = 1,但是两者是只算一个匹配。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 40 + 20;
char str[maxn][maxn];
int a[maxn][maxn];
struct Node {
    int u, v, tonext;
}e[maxn * maxn * 3];
int first[maxn * maxn * 3], num;
void addEdge(int u, int v) {
    ++num;
    e[num].u = u, e[num].v = v;
    e[num].tonext = first[u];
    first[u] = num;
}
int match[maxn * maxn * 3], book[maxn * maxn * 3], DFN;
bool dfs(int u) {
    for (int i = first[u]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (book[v] == DFN) continue;
        book[v] = DFN;
        if (match[v] == 0 || dfs(match[v])) {
            match[v] = u;
            return true;
        }
    }
    return false;
}
vector<int>vc;
int hungary() {
    memset(match, 0, sizeof match);
    int ans = 0;
    for (int i = 0; i < vc.size(); ++i) {
        ++DFN;
        if (dfs(vc[i])) ans++;
    }
    return ans;
}
int col[maxn * maxn * 3];
void ran(int cur, int which) {
    col[cur] = which;
    book[cur] = DFN;
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (book[v] == DFN) continue;
        ran(v, !which);
    }
}
void work() {
    memset(first, 0, sizeof first);
    num = 0;
    int to = 0;
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        scanf("%s", str[i] + 1);
    }
    memset(a, 0, sizeof a);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (str[i][j] == ‘*‘) {
                a[i][j] = ++to;
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (a[i][j + 1]) addEdge(a[i][j], a[i][j + 1]);
            if (a[i + 1][j]) addEdge(a[i][j], a[i + 1][j]);
            if (a[i][j - 1]) addEdge(a[i][j], a[i][j - 1]);
            if (a[i - 1][j]) addEdge(a[i][j], a[i - 1][j]);
        }
    }
    memset(col, -1, sizeof col);
    ++DFN;
    for (int i = 1; i <= to; ++i) {
        if (book[i] != DFN) ran(i, 0);
    }
    vc.clear();
    for (int i = 1; i <= to; ++i) {
        if (col[i] == 1) vc.push_back(i);
    }
    cout << to - hungary() << endl;
}

int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    int t;
    cin >> t;
    while (t--) work();
    return 0;
}

时间: 2024-08-01 10:45:44

POJ - 3020 ? Antenna Placement 二分图最大匹配的相关文章

POJ 3020 Antenna Placement(二分图建图训练 + 最小路径覆盖)

题目链接:http://poj.org/problem?id=3020 Antenna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6692   Accepted: 3325 Description The Global Aerial Research Centre has been allotted the task of building the fifth generation of mobi

POJ 3020 Antenna Placement(二分图 匈牙利算法)

题目网址:  http://poj.org/problem?id=3020 题意: 用椭圆形去覆盖给出所有环(即图上的小圆点),有两种类型的椭圆形,左右朝向和上下朝向的,一个椭圆形最多可以覆盖相邻的两个小圆点.   思路: 将每个小圆点看作是一个顶点,因为一个椭圆只能覆盖两个小圆点,我们就可以把这个图看成一个二分图.将相邻的两个点,一个看作是X集合内顶点,另一个看成是Y集合内顶点.但要注意的是一个顶点可能不止和一个顶点想连(如上图情况),所以我们要把上述情况看作是一个无向图,而不是有向图.无向图

POJ - 3020 Antenna Placement 二分图 最小路径覆盖

题目大意:有n个城市,要在这n个城市上建立无线电站,每个无线电站只能覆盖2个相邻的城市,问至少需要建多少个无线电站 解题思路:英语题目好坑,看了半天.. 这题和POJ - 2446 Chessboard类似 可以将所有城市分成两个点集,那么之间的连线就代表无线电站的覆盖关系了. 因为所有城市都要覆盖到,所以根据关系,求出最小路径覆盖就能覆盖所有城市了 #include<cstdio> #include<algorithm> #include<cstring> #incl

POJ 3020 Antenna Placement ,二分图的最小路径覆盖

题目大意: 一个矩形中,有N个城市'*',现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市. 问至少放置多少个基站才能使得所有的城市都覆盖无线? 无向二分图的最小路径覆盖 = 顶点数 –  最大二分匹配数/2 路径覆盖就是在图中找一些路径,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联: #include<cstdio> #include<cstring> #include<vector> #include<algor

POJ 3020 Antenna Placement(二分图匹配)

POJ 3020 Antenna Placement 题目链接 题意:给定一个地图,'*'的地方要被覆盖上,每次可以用1 x 2的矩形去覆盖,问最少用几个能覆盖 思路:二分图匹配求最大独立集,相邻*之间连边,然后求最大独立集即可 看这数据范围,用轮廓线dp应该也能搞 代码: #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace s

二分图匹配(匈牙利算法) POJ 3020 Antenna Placement

题目传送门 1 /* 2 题意:*的点占据后能顺带占据四个方向的一个*,问最少要占据多少个 3 匈牙利算法:按坐标奇偶性把*分为两个集合,那么除了匹配的其中一方是顺带占据外,其他都要占据 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <vector> 9 using namespace std; 10 11 const int MAXN = 4e

poj 3020 Antenna Placement 解题报告

题目链接:http://poj.org/problem?id=3020 题目意思:首先,请忽略那幅有可能误导他人成分的截图(可能我悟性差,反正有一点点误导我了). 给出一幅 h * w 的图,  “ * ” 表示 point of interest,“ o ” 忽略之.你可以对 " * " (假设这个 “* ”的坐标是 (i, j))画圈,每个圈只能把它四周的某一个点括住(或者是上面(i-1, j) or 下面(i+1, j) or 左边(i, j-1)  or 右边(i, j+1))

POJ训练计划3020_Antenna Placement(二分图/最大匹配)

解题报告 题目传送门 题意: 在h×w的矩阵中,o表示空地,*表示城市,无线设备只能装在城市上,要使城市全都覆盖需要多少设备.每个设备只能覆盖相邻的两个设备. 思路: 感觉是直接的最大匹配,求出两两匹配的最大数,加上没有匹配的城市就是要的答案. 网上看了题解,正解是最小路径覆盖. 最小路径覆盖=|G|-最大匹配数 在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点, 且任何一个顶点有且只有一条路径与之关联:(如果把这些路径中的每条路径从它的起始点走到它的终点, 那么恰

poj 3020 Antenna Placement(最小路径覆盖 + 构图)

http://poj.org/problem?id=3020 Antenna Placement Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7565   Accepted: 3758 Description The Global Aerial Research Centre has been allotted the task of building the fifth generation of mobile ph