长脖子鹿放置

link

有些东西呢比较玄学,其中水太深你把握不住。

这道题首先有个小小的创新,即平常的染色方法无法把它变成二分图,从题目中的图片来看,长颈鹿从白色方格跳跃到了白色方格,二分图二分了个寂寞。这很好解决,小学奥数都学过对图各种各样的染色,对于这道题隔列染色就能解决问题。然后二分图交了一发40分。感谢评论区的大哥让我知道障碍重复的问题,但还是T了两个点。然后题解区第一篇给了灵感,只需要调换一下加边顺序,把可能匹配到新点的边尽量后加,这样一来find的时候就可以先看到这条边,就避免了打扰别人的过程,从而极大地(10倍)提升程序效率。也可以写网络流,但既然二分图匹配可以过那就懒得写网络流了。

#include<bits/stdc++.h>
//#define feyn
const int N=210;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

int m,n,num,a[N][N],cnt,sum;
bool d[N][N];
int f[8][2]={{-1,-3},{-3,-1},{-1,3},{3,-1},{-3,1},{1,3},{3,1},{1,-3}};
inline bool check(int x,int y){
	return x<1||y<1||x>m||y>n||d[x][y];
}

struct edge{
	int t,next;
}e[N*N*10];
int head[N*N],esum;
inline void add(int fr,int to){
	e[++esum]=(edge){to,head[fr]};head[fr]=esum;
}

int c[N*N],t[N*N],nt=1;
inline bool find(int wh){
	for(int i=head[wh],th;i;i=e[i].next){
		if(t[th=e[i].t]==nt)continue;t[th]=nt;
		if(c[th]==0||find(c[th]))return c[th]=wh,true;
	}
	return false;
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++)a[i][j]=++cnt;
	}
	read(num);int s1,s2;
	for(int i=1;i<=num;i++){
		read(s1);read(s2);
		if(d[s1][s2]==false)sum++;
		d[s1][s2]=true;
	}
	for(int i=1;i<=m;i+=2){
		for(int j=1;j<=n;j++){
			if(d[i][j])continue;
			for(int k=0;k<8;k++){
				int x=i+f[k][0],y=j+f[k][1];
				if(check(x,y))continue;
				add(a[i][j],a[x][y]);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=cnt;i++,nt++)ans+=find(i);
	printf("%d",n*m-sum-ans);
	
	return 0;
}
posted @ 2022-07-11 15:11  Feyn618  阅读(26)  评论(0编辑  收藏  举报