[P5030] 长脖子鹿放置

Description:

西洋棋的“长脖子鹿”,类似于中国象棋的马,但按照“目”(1*3)字攻击,且没有中国象棋“别马腿”的规则。(因为长脖子鹿没有马腿)
给定一个N∗M,的棋盘,有一些格子禁止放棋子。问棋盘上最多能放多少个不能互相攻击的长脖子鹿。

Hint:

\(n \le 200\)

Solution:

和骑士共存那题一样的套路,不过由于是1*3,就按行奇偶性建边

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=2e5+5,inf=1e9;
int S,T,n,m,k,cnt,ans,dep[mxn],cur[mxn],mp[500][500],hd[mxn];
int dx[9]={1,1,-1,-1,3,3,-3,-3};
int dy[9]={3,-3,3,-3,1,-1,1,-1};

inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct ed {
    int to,nxt,w;
}t[mxn<<1];

inline void add(int u,int v,int w) {
    t[cnt]=(ed) {v,hd[u],w}; hd[u]=cnt++;
    t[cnt]=(ed) {u,hd[v],0}; hd[v]=cnt++;
}

int bfs() {
    memset(dep,0,sizeof(dep)); queue<int > q;
    q.push(S); dep[S]=1;
    for(int i=0;i<=n*m+1;++i) cur[i]=hd[i];
    while(!q.empty()) {
        int u=q.front(); q.pop();
        for(int i=hd[u];i!=-1;i=t[i].nxt) {
            int v=t[i].to;
            if(dep[v]==0&&t[i].w>0) 
                dep[v]=dep[u]+1,q.push(v);
        }
    }
    if(dep[T]==0) return 0;
    return 1;
}

int dfs(int u,int f) {
    if(u==T) return f;
    for(int &i=cur[u];i!=-1;i=t[i].nxt) {
        int v=t[i].to;
        if(dep[v]==dep[u]+1&&t[i].w>0) {
            int tp=dfs(v,min(f,t[i].w));
            if(tp>0) {
                t[i].w-=tp;
                t[i^1].w+=tp;
                return tp;
            }
        }
    }
    return 0;
}

void Dinic() {
    while(bfs())
        while(int tp=dfs(S,inf)) 
            {ans+=tp;}
}

int get(int x,int y) {
	return (x-1)*m+y;
}

int main()
{
	memset(hd,-1,sizeof(hd));
	n=read(); m=read(); k=read(); T=n*m+1; int x,y;
    for(int i=1;i<=k;++i) x=read(),y=read(),mp[x][y]=1;
	for(int i=1;i<=n;++i) 
		for(int j=1;j<=m;++j) 
			if(i&1) add(S,get(i,j),1);
			else add(get(i,j),T,1);
	for(int i=1;i<=n;++i) 
		for(int j=1;j<=m;++j) 
			if(i&1) for(int k=0;k<8;++k) {
				x=i+dx[k],y=j+dy[k];
				if(x<1||y<1||x>n||y>m||mp[x][y]||mp[i][j]) continue ;
				add(get(i,j),get(x,y),1);
			}
	Dinic(); printf("%d",n*m-k-ans);		
	return 0; 
}

posted @ 2019-03-24 21:38  cloud_9  阅读(170)  评论(0编辑  收藏  举报