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

来源:互联网 发布:linux可执行文件结构 编辑:程序博客网 时间:2024/06/02 05:44


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;}


0 0