[网络流24题]骑士共存问题

题目描述

二分图最大点独立集问题。

要求在棋盘上放最多互不攻击的骑士,即在棋盘中拿走最少的骑士,使得剩下的骑士互不攻击。

黄格只能攻击红格,红格也只能攻击黄格,所以考虑建立二分图。

源点向所有红格连流量为1的边,所有黄格向汇点连流量为一的边,再由红格向它能攻击到的黄格连流量为1的边,有障碍物的点不连边。

每找到一条增广路,即从棋盘中拿走一个骑士,所以最后的答案就是总点数-障碍数-最大匹配数。

#include<complex>
#include<cstdio>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=4e4+7;
const int dx[]={-1,-1,1,1,-2,-2,2,2},dy[]={-2,2,-2,2,-1,1,-1,1};
struct node{
    int v,f,nxt;
}e[N*10];
int n,m,Enum=1,s,t;
int front[N],cur[N],deep[N];
int q[N];
bool vis[201][201];
int qread()
{
    int x=0;
    char ch=getchar();
    while(ch<'0' || ch>'9')ch=getchar();
    while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
void Insert(int u,int v,int w)
{
    e[++Enum].v=v;e[Enum].f=w;e[Enum].nxt=front[u];front[u]=Enum;
    e[++Enum].v=u;e[Enum].f=0;e[Enum].nxt=front[v];front[v]=Enum;
}
bool bfs()
{
    for(int i=0;i<=t;i++)
    {
        deep[i]=0;
        cur[i]=front[i];
    }
    int head=1,tail=0,u,v;
    deep[s]=1;q[++tail]=s;
    while(head<=tail)
    {
        u=q[head++];
        for(int i=front[u];i;i=e[i].nxt)
        {
            v=e[i].v;
            if(!deep[v] && e[i].f)
            {
                deep[v]=deep[u]+1;
                if(v==t)return 1;
                q[++tail]=v;
            }
        }
    }
    return 0;
}
int dfs(int x,int cur_flow)
{
    if(x==t)return cur_flow;
    int rest=cur_flow,v;
    for(int &i=cur[x];i;i=e[i].nxt)
    {
        v=e[i].v;
        if(deep[v]==deep[x]+1 && e[i].f && rest)
        {
            int new_flow=dfs(v,min(e[i].f,rest));
            e[i].f-=new_flow;
            e[i^1].f+=new_flow;
            rest-=new_flow;
            if(!rest)return cur_flow;
        }
    }
    deep[x]=0;
    return cur_flow-rest;
}
int Dinic()
{
    int res=0;
    while(bfs())
        res+=dfs(s,INF);
    return res;
}
bool can(int x,int y)
{
    if(x<1 || x>n || y<1 || y>n || vis[x][y])return 0;
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    s=0;t=n*n+1;
    for(int i=1;i<=m;i++)
        vis[qread()][qread()]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!vis[i][j])
                if((i+j)&1)
                    Insert(s,(i-1)*n+j,1);
                else Insert((i-1)*n+j,t,1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!vis[i][j] && (i+j)&1)
                for(int k=0;k<8;k++)
                {
                    int xx=i+dx[k],yy=j+dy[k];
                    if(can(xx,yy))
                        Insert((i-1)*n+j,(xx-1)*n+yy,1);
                }
    printf("%d
",n*n-m-Dinic());
    return 0;
}
原文地址:https://www.cnblogs.com/LeTri/p/9029989.html