poj3020

一些常用性质:


对于无向图:

最小点覆盖+最大独立集=顶点个数

最大团=补图的最大独立子集

关系1:给定图G = (V,E)无孤立点,则G的极大点独立集都是G的极小支配集。

关系2:G的点覆盖数 a与点独立集数 b满足: a + b = n。

关系3:G的边覆盖数 a与边独立集数 b满足: a + b = n。(边独立集数即匹配数)

关系3:给定图G = (V,E)无孤立点,|V | = n。M是G的匹配,W是G的边覆盖,则|M|≤|W|,等号成立时M是G的完美匹配而W是G的最小边覆盖。


对于二部图

最小点覆盖数 = 最大匹配数

最小路径覆盖 = 顶点数 – 最大(二分)匹配数 / 2;

关于二分图最大匹配,这里讲的很详细http://dsqiu.iteye.com/blog/1689505

关于这道题,其实就是先把“*"看成点,然后看可以覆盖的相邻点,两者相连,接着用上面公式求最小路径覆盖

#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <stack>
#include <iomanip>
using namespace std;
int  mapp[45][15],g[505][505],pp[500],n;
bool visit[500];
int d[4][2]={1,0,0,1,-1,0,0,-1};
bool findd(int x)
{
    for(int i=1;i<=n;i++)
    {
        if(!visit[i]&&g[x][i])
        {
            visit[i]=1;
            if(pp[i]==-1||findd(pp[i]))
            {
            pp[i]=x;
            return true;
            }
        }
    }
    return false;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int r,c;
        n=0;
        cin>>r>>c;
        memset(mapp,0,sizeof(mapp));
        memset(pp,-1,sizeof(pp));
        memset(g,0,sizeof(g));
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
        {
           char e;
           cin>>e;
            if(e=='*')
            {
               mapp[i][j]=++n;
            }
        }
        for(int i=1;i<=r;i++)
            for(int j=1;j<=c;j++)
        {
            if(mapp[i][j])
            {
                for(int k=0;k<4;k++)
                {
                    int xi=i+d[k][0];
                    int yi=j+d[k][1];
                    if(xi>=1&&xi<=r&&yi>=1&&yi<=c&&mapp[xi][yi])
                        g[mapp[i][j]][mapp[xi][yi]]=1;
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            memset(visit,0,sizeof(visit));
            if(findd(i))ans++;
        }
        //cout<<n<<' '<<ans<<endl;
        ans=n-(ans/2);
        cout<<ans;
        cout<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值