1. 程式人生 > >BZOJ4808馬——二分圖最大獨立集

BZOJ4808馬——二分圖最大獨立集

過去 正整數 這一 多個 情況 highlight nbsp ace pri

題目描述

眾所周知,馬後炮是中國象棋中很厲害的一招必殺技。"馬走日字"。本來,如果在要去的方向有別的棋子擋住(俗 稱"蹩馬腿"),則不允許走過去。為了簡化問題,我們不考慮這一點。馬跟馬顯然不能在一起打起來,於是rly在 一天再次借來了許多許多的馬在棋盤上擺了起來……但這次,他實在沒興趣算方案數了,所以他只想知道在N×M的 矩形方格中擺馬使其互不吃到的情況下的最多個數。但是,有一個很不幸的消息,rly由於玩得太Happy,質量本來 就不好的棋盤被rly弄壞了,不過幸好只是破了其中的一些格子(即不能再放子了),問題還是可以繼續解決的。

輸入

一行,兩個正整數N和M。 接下來N行,每行M個數,要麽為0,表示沒壞,要麽為1,表示壞了。 N<=200,M<=200

輸出

一行,輸出最多的個數。

樣例輸入

2 3
0 1 0
0 1 0

樣例輸出

2   這道題和BZOJ3175是一樣的題,黑白染色之後跑二分圖最大匹配,用矩陣大小-1的數目-二分圖最大匹配數。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int next[1000001];
int to[1000001];
int val[1000001];
int head[1000001];
int tot=1;
int q[1000001];
int n,k,m;
int S,T;
int ans;
int x,y;
int d[1000001];
int c[1001][1001];
const int dx[]={-2,-1,1,2,2,1,-1,-2};
const int dy[]={1,2,2,1,-1,-2,-2,-1};
void add(int x,int y,int v)
{
    tot++;
    next[tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    val[tot]=v;
    tot++;
    next[tot]=head[y];
    head[y]=tot;
    to[tot]=x;
    val[tot]=0;
} 
bool bfs(int S,int T)
{
    int r=0;
    int l=0;
    memset(q,0,sizeof(q));
    memset(d,-1,sizeof(d));
    q[r++]=S;
    d[S]=0;
    while(l<r)
    {  
        int now=q[l];
        for(int i=head[now];i;i=next[i])
        {
            if(d[to[i]]==-1&&val[i]!=0)
            {
                d[to[i]]=d[now]+1;
                q[r++]=to[i];
            }
        }
        l++;
    }
    if(d[T]==-1)
    {
        return false;
    }
    else
    {
        return true;
    }
}
int dfs(int x,int flow)
{
    if(x==T)
    {
        return flow;
    }
    int now_flow;
    int used=0;
    for(int i=head[x];i;i=next[i])
    {
        if(d[to[i]]==d[x]+1&&val[i]!=0)
        {
            now_flow=dfs(to[i],min(flow-used,val[i]));
            val[i]-=now_flow;
            val[i^1]+=now_flow;
            used+=now_flow;
            if(now_flow==flow)
            {
                return flow;
            }
        }
    }
    if(used==0)
    {
        d[x]=-1;
    }
    return used;
}
void dinic()
{
    while(bfs(S,T)==true)
    {
        ans+=dfs(S,0x3f3f3f);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    S=n*m+16;
    T=n*m+28;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&c[i][j]);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(c[i][j]==0)
            {
                c[i][j]=(i-1)*m+j;
                if((i+j)%2==0)
                {
                    add(S,c[i][j],1);
                }
                else
                {
                    add(c[i][j],T,1);
                }
            }
            else
            {
                k++;
                c[i][j]=-1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(c[i][j]!=-1&&(i+j)%2==0)
            {
                for(int l=0;l<=7;l++)
                {
                    int fx=dx[l]+i;
                    int fy=dy[l]+j;
                    if(fx>0&&fx<=n&&fy>0&&fy<=m&&c[fx][fy]!=-1)
                    {
                        add(c[i][j],c[fx][fy],0x3f3f3f);
                    } 
                }
            }
        }
    }
    dinic();
    printf("%d",n*m-k-ans);
}

BZOJ4808馬——二分圖最大獨立集