BZOJ 4808: 马(二分图最大点独立集)

 http://www.lydsy.com/JudgeOnline/problem.php?id=4808

题意:

 

思路:

这图中的两个马只能选一个,二选一,很像二分图吧,对能互吃的两个棋子连线,在所选的任意两个棋子中,都不能互相有连线,这不就是最大点独立集吗?

最大独立集 = 顶点个数 - 最大匹配。记得把坏了的格子去掉。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int n,m,tot;
int mp[205][205], head[40005], mark[40005];
bool vis[40005];

struct node
{
    int v,next;
}e[8*40005];

int dx[] = {-2,-2,-1,-1,1,1,2,2};
int dy[] = {1,-1,2,-2,2,-2,1,-1};

void addEdge(int u, int v)
{
    e[tot].v = v;
    e[tot].next = head[u];
    head[u] = tot++;
}

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

int main()
{
    //freopen("in.txt","r",stdin);
    int num = 0;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        scanf("%d",&mp[i][j]);
        if(mp[i][j]) num++;
    }
    tot = 0;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        if(!mp[i][j])
        {
            for(int k=0;k<8;k++)
            {
                int x = i+dx[k];
                int y = j+dy[k];
                if(x<1 || x>n || y<1 || y>m)  continue;
                if(mp[x][y]==1)  continue;
                int p1 = (i-1)*m+j;
                int p2 = (x-1)*m+y;
                addEdge(p1,p2);
            }
        }
    }
    int sum = 0;
    memset(mark,-1,sizeof(mark));
    for(int i=1;i<=n*m;i++)
    {
        memset(vis,false,sizeof(vis));
        if(match(i))  sum++;
    }
    printf("%d
",n*m-num-sum/2);
    return 0;
}

  

原文地址:https://www.cnblogs.com/zyb993963526/p/7904002.html