网络流24题——骑士共存问题 luogu 3355

题目描述:这里

从这里开始,我们涉及到了一个新的问题:最小割问题

首先给出一些定义(本人根据定义自己口胡的):

一个流网络中的一个割是一个边集,使得割掉这些边集后源点与汇点不连通

而最小割问题就是一个使得边集中各边容量之和最小的割

根据ford-fulkerson定理,最小割等于最大流!

基于上面的定义,我们可以来讨论这道题了:

首先,根据套路,棋盘经过黑白染色之后可以形成一个二分图,我们由源点向黑点连边,白点向汇点连边,然后由黑点向白点连边,权值为1(所有不能用的点不做考虑)

然后跑一遍最小割,用总和减去最小割即可

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
const int inf=0x3f3f3f3f;
struct Edge
{
    int next;
    int to;
    int val;
}edge[500005];
int head[100005];
int dir[8][2]={{2,1},{1,2},{1,-2},{2,-1},{-1,-2},{-2,-1},{-1,2},{-2,1}};
bool used[2005][2005];
int dis[100005];
int cur[100005];
int cnt=1;
int n,m;
int st,ed;
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void add(int l,int r,int w)
{
    edge[cnt].next=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
bool check(int x,int y)
{
    return (x>=1)&&(x<=n)&&(y>=1)&&(y<=n)&&(!used[x][y]);
}
int ide(int x)
{
    return (x&1)?x+1:x-1;
}
int idx(int x,int y)
{
    return (x-1)*n+y;
}
bool bfs()
{
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    dis[st]=1;
    queue <int> M;
    M.push(st);
    while(!M.empty())
    {
        int u=M.front();
        M.pop();
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int to=edge[i].to;
            if(edge[i].val&&!dis[to])dis[to]=dis[u]+1,M.push(to);
        }
    }
    return dis[ed];
}
int dfs(int x,int lim)
{
    if(x==ed)return lim;
    int ret=0;
    for(int i=cur[x];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(edge[i].val&&dis[to]==dis[x]+1)
        {
            int temp=dfs(to,min(lim,edge[i].val));
            if(temp)
            {
                lim-=temp;
                ret+=temp;
                edge[i].val-=temp;
                edge[ide(i)].val+=temp;
                if(!lim)break;
            }
        }
        cur[x]=i;
    }
    return ret;
}
int dinic()
{
    int ret=0;
    while(bfs())ret+=dfs(st,inf);
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);
    st=n*n+1,ed=n*n+2;
    init();
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        used[x][y]=1;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(used[i][j])continue;
            if((i+j)&1)
            {
                add(st,idx(i,j),1);
                add(idx(i,j),st,0);
                for(int k=0;k<8;k++)
                {
                    int x=i+dir[k][0];
                    int y=j+dir[k][1];
                    if(check(x,y))add(idx(i,j),idx(x,y),inf),add(idx(x,y),idx(i,j),0);
                }
            }else
            {
                add(idx(i,j),ed,1);
                add(ed,idx(i,j),0);
            }
        }
    }
    printf("%d\n",n*n-m-dinic());
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhangleo/p/10774425.html
今日推荐