POJ3020,最小边覆盖

说来惭愧,看了别人的题解之后知道解题步骤,却不知道原理,也就是说,不知其所以然,哎…
步骤就是:将所有相邻的点建立无向图,之后求最小边覆盖,即为答案。

/*************************************************************************
    > File Name: main.cpp
    > Author:Eagles 
    > Mail:None 
    > Created Time: 2018年09月15日 星期六 21时42分11秒
    > Description:POJ3020 
 ************************************************************************/

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
#define N 1000
struct node
{
    int to;
    int nex;
}E[N*N];
int head[N];
int map[N][N];
int vis[N];
int pre[N];
int n,cnt;
int h,w;
bool city[N][N];

int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};

void addEdge(int a, int b)
{
    E[cnt].to=b;
    E[cnt].nex=head[a];
    head[a]=cnt++;
}

bool check(int x, int y)
{
    return (0<=x&&x<h&&0<=y&&y<w&&map[x][y]);
}

void init()
{
    memset(head,-1,sizeof(head));
    memset(pre,-1,sizeof(pre));
    memset(city,false,sizeof(city));
    memset(map,0,sizeof(map));
    cnt=n=0;

    for (int i=0; i<h; i++)
    {
        for (int j=0; j<w; j++)
        {
            char ch;
            scanf("%c",&ch);
            if (ch=='*')
                map[i][j]=++n;
        }
        getchar();
    }

    for (int i=0; i<h; i++)
    {
        for (int j=0; j<w; j++)
        {
            if (map[i][j])
            {
                for (int k=0; k<4; k++)
                {
                    int x=i+dir[k][0];
                    int y=j+dir[k][1];

                    if (check(x,y))
                    {
                        city[map[i][j]][map[x][y]]=true;
                    }
                }
            }
        }
    }

    for (int i=0; i<=n; i++)
    {    for (int j=0; j<=n; j++)
        {
            if (city[i][j])
                addEdge(i,j);
        }
    }
}

int dfs(int x)
{
    for (int i=head[x]; i!=-1; i=E[i].nex)
    {
        if (!vis[E[i].to])
        {
            vis[E[i].to]=true;
            if (pre[E[i].to]==-1||dfs(pre[E[i].to]))
            {
                pre[E[i].to]=x;
                return 1;
            }
        }
    }
    return 0;
}

int hungary()
{
    int sum=0;

    for (int i=1; i<=n; i++)
    {
        memset(vis,false,sizeof(vis));
        if (dfs(i))
            sum++;
    }

    return n-sum/2;
}

int main()
{
    int t;
    while (~scanf("%d",&t))
    {
        while (t--)
        {
            scanf("%d%d",&h,&w);
            getchar();
            init();
            printf("%d\n",hungary());
        }
    }
    return 0;
}
发布了45 篇原创文章 · 获赞 2 · 访问量 3087

猜你喜欢

转载自blog.csdn.net/wysiwygo/article/details/82719113