CF1638D 菜鸡求助(代码有注释,可能悬赏关注)
查看原帖
CF1638D 菜鸡求助(代码有注释,可能悬赏关注)
239895
Yusani_huh楼主2022/7/25 19:21

我的代码已经写到不能再暴力了

显示第四个点有可行解但输出 -1

#include<bits/stdc++.h>
using namespace std;
#define N 1003
#define LL long long
#define INF 0x3f3f3f3f
int n,m,h[N][N],tp,tot;
struct node{
	int x,y,k;
}stk[8000003],ans[8000003];
int dxb[4]={-1,0,1,0};  //检查边的方向数组(使用见下面的函数)
int dxbfz[8]={0,0,0,1,1,1,0,1};  //检查边的方向辅助数组(使用见下面的函数)
int dyb[4]={0,1,0,-1};
int dybfz[8]={0,1,1,1,0,1,0,0};
int dxj[4]={-1,-1,1,1};  //检查角的方向数组(使用见下面的函数)
int dxjfz[12]={1,0,0,0,0,1,0,1,1,1,1,0};  //检查角的方向辅助数组(使用见下面的函数)
int dyj[4]={-1,1,1,-1};
int dyjfz[12]={0,0,1,0,1,1,1,1,0,1,0,0};
void chkb(int x,int y){  //检查被删除大方格的上下左右四条边(即上下左右是否有一半的大方格)
	for(int d=0;d<4;d++){
		int xx=x+dxb[d],yy=y+dyb[d];
		//被操作的点,即需要在答案中输出的点
		if(xx<1||xx>=n||yy<1||yy>=m) continue;
		int xa=xx+dxbfz[d*2],ya=yy+dybfz[d*2];
		int xb=xx+dxbfz[d*2+1],yb=yy+dybfz[d*2+1];
		//上面两个是需要检查的点,即上述“一半的大方格”中的两个点
		int num=0;
		if(h[xa][ya]) num=h[xa][ya];
		if(h[xb][yb]) num=h[xb][yb];
		if(!h[xa][ya]) h[xa][ya]=num;
		if(!h[xb][yb]) h[xb][yb]=num;
		//这五行意为检查点是否都为零,若有点不为零则把为零的点全改为那个点的值(方便检查)
		if(num&&h[xa][ya]==num&&h[xb][yb]==num){  //如果两个点值相等则可能为上述“一半的大方格”,加入答案
			stk[++tp]={xx,yy,num},ans[++tot]={xx,yy,num};
			h[xa][ya]=h[xb][yb]=0;
		}
	}
}
void chkj(int x,int y){  //检查被删除大方格的四个角(即四个角是否有缺一角的大方格)
	for(int d=0;d<4;d++){
		int xx=x+dxj[d],yy=y+dyj[d];  //被操作的点
		if(xx<1||xx>=n||yy<1||yy>=m) continue;
		int xa=xx+dxjfz[d*3],ya=yy+dyjfz[d*3];
		int xb=xx+dxjfz[d*3+1],yb=yy+dyjfz[d*3+1];
		int xc=xx+dxjfz[d*3+2],yc=yy+dyjfz[d*3+2];  //需检查的点
		int num=0;
		if(h[xa][ya]) num=h[xa][ya];
		if(h[xb][yb]) num=h[xb][yb];
		if(h[xc][yc]) num=h[xc][yc];
		if(!h[xa][ya]) h[xa][ya]=num;
		if(!h[xb][yb]) h[xb][yb]=num;
		if(!h[xc][yc]) h[xc][yc]=num;  //同上个函数
		if(num&&h[xa][ya]==num&&h[xb][yb]==num&&h[xc][yc]==num){
			stk[++tp]={xx,yy,num},ans[++tot]={xx,yy,num};
			h[xa][ya]=h[xb][yb]=h[xc][yc]=0;
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			scanf("%d",&h[i][j]);
	for(int i=1;i<n;++i)
		for(int j=1;j<m;++j)
			if(h[i+1][j]==h[i][j]&&h[i][j+1]==h[i][j]&&h[i+1][j+1]==h[i][j]){  //如果初始有完整的大方格则直接清空加入答案
				stk[++tp]={i,j,h[i][j]},ans[++tot]={i,j,h[i][j]};
				h[i][j]=h[i+1][j]=h[i][j+1]=h[i+1][j+1]=0;
			}
	while(tp){  //每次取栈顶检查四周是否有可能完整的大方格
		int x=stk[tp].x,y=stk[tp].y;
		tp--,chkb(x,y),chkj(x,y);
	}
	bool fl=false;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(h[i][j]) fl=true;  //如果仍有点未被染色则无解
	if(fl) puts("-1");
	else{
		printf("%d\n",tot);
		for(int i=tot;i;--i)  //输出答案
			printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].k);
	}
	return 0;
}
2022/7/25 19:21
加载中...