长脖子鹿放置(最大流)

题意还是很容易理解的  感觉同(骑士共存问题)

主要就是建图了

将棋盘进行染色,这次不同于骑士共存那道题,这次直接对第几行染色

证明的话,自己yy了一个:

因为每一行无法到达的只有相邻的两行,那么就可以分情况了

若一行行数为奇数,那么将其与超级源点相连,流量为1

反之亦然,于超级汇点相连,同理流量为1

对于那些障碍点直接判掉就好了,

这样的话跟上面一样,在遍历整个图同时将不同的点进行相连,流量为INF,表示一种相连关系

最后愉快的跑一下最大流即可

题面

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
const int INF=0x7f7f7f7f;
int m,n,k,p,s,t,cnt=1,ans,tot;
int dx[9]={0,-3,-3,-1,-1,1,1,3,3},dy[9]={0,-1,1,-3,3,-3,3,-1,1};
struct node
{
    int nx,to,flow;
} e[N];
int id(int x,int y) {return (x-1)*m+y;}
int dep[N],head[N];
void add_edge(int a,int b,int flow)
{
    cnt++;e[cnt].flow=flow;e[cnt].nx=head[a];e[cnt].to=b;head[a]=cnt;
    cnt++;e[cnt].flow=0;e[cnt].nx=head[b];e[cnt].to=a;head[b]=cnt;
}
bool used[210][210];
bool bfs(int s,int t)
{
    queue<int> que;memset(dep,0,sizeof(dep));
    que.push(s);dep[s]=1;
    while (!que.empty())
    {
        int x=que.front();que.pop();
        for (int i=head[x];i;i=e[i].nx)
        {
            int y=e[i].to;
            if (dep[y]==0&&e[i].flow)
            {
                dep[y]=dep[x]+1;
                que.push(y);
            }
        }
    }
  if (dep[t]==0) return false;
  else return true;
}
int dfs(int x,int limit,int t)
{
    if (x==t) return limit;
    int used=0;
    for (int i=head[x];i;i=e[i].nx)
    {
        int y=e[i].to;
        if (dep[y]==dep[x]+1&&e[i].flow>0)
        {
            int di=dfs(y,min(limit-used,e[i].flow),t);
            if (di>0)
            {
                e[i].flow-=di;
                e[i^1].flow+=di;
                used+=di;
                if (used==limit) return used;
            }
        }
    }
  if (!used) dep[x]=-2;
  return used;
}
void dinic(int s,int t)
{
    while (bfs(s,t)) 
    {ans+=dfs(s,INF,t);
     tot++;}
}
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    s=N-3;t=N-4;
    for (int i=1;i<=p;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        used[x][y]=true;
    }
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
    if (!used[i][j])
    {
        if (i%2==1) add_edge(s,id(i,j),1);
        else add_edge(id(i,j),t,1);
    }
    for (int i=1;i<=n;i++)
     for (int j=1;j<=m;j++)
     {
         if (i%2!=1) continue;
         for (int k=1;k<=8;k++)
         {
             int x=i+dx[k],y=j+dy[k];
             if (x<=0||y<=0||x>n||y>m) continue;
             if (used[x][y]) continue;
             add_edge(id(i,j),id(x,y),INF);
         }
     }
    dinic(s,t);
    printf("%d",n*m-ans-p);
    return 0; 
}
慢即是快,细则是能,于小处铸迤逦
原文地址:https://www.cnblogs.com/Hale522520/p/10630742.html