NOIP试题详讲2021/11/2

T1

题目描述
数独是一个有趣的游戏。你需要在一个9×9 的矩阵中的每个格子中填入1 ~
9 的数字,使得没有两个相同的数字填入同一行、同一列或同一个九宫格中。
整个矩阵被划分为9 个九宫格,若两个格子同时在最左三列、最右三列或中
间三列,且同时在最左三行、最右三行或中间三行,则这两个格子在同一九宫格
中。
如果两个相同的数同行、同列或同九宫格,则构成一对冲突。

现在有一个数独的初始状态,出题人想对其进行一些修改和询问操作。需要
注意:在操作时,初始状态中的数也可以被删除或者合并时被替换。

  1. 向目前状态中的指定位置填入一个数:但有可能这个位置已经有一个数
    了,此时你需要输出一行 Error!,然后不进行这次修改操作;在指定的
    这个位置没有数的情况下,这个数已经与之前存在的在同一行、列或九
    宫格中的数构成冲突,此时,你需要按照行、列、九宫格的顺序,找到
    第一种冲突的情况,输出一行Error:row! ,Error:column!或
    Error:square!,然后不进行这次修改操作;否则,你需要输出OK! ,
    并在指定位置填入该数。

  2. 删除目前状态中的一个位置上的数:若这个位置没有数字,此时你需要
    输出一行Error!,然后不进行任何操作;否则你需要输出一行 OK! ,并
    将该位置的数删除。

  3. 查询目前状态中的某个位置能填入多少种数字;若被查询的位置已经有
    数字了,你需要输出一行 Error!;否则,输出一行一个整数 n 表示能填
    入的数字个数,随后n 行每行一个整数,按照从小到大的顺序输出能填
    入的数字。

  4. 将之前的第i 次操作后的数独状态和第j 次操作后的数独状态进行合并,
    作为当前状态。需要注意:对于所有的5 种操作,包括但不限于出现
    Error!或是没有进行任何修改,均被算作一次操作。合并时以行为第一
    关键字,列为第二关键字的顺序依次考虑每个格子,若第i 次操作后的
    数独状态中该位置有数且不会与之前冲突则优先填入;否则,在不会与
    之前冲突的情况下,填入第j 次操作后的数独状态中该位置的数。若均
    没有数字或均与本次合并中已填入的数字冲突,则不填入任何数。输出
    一行,包含空格隔开的两个整数,表示最终的结果中有多少数字来自第
    i 次操作后的数独状态中,多少来自第j 次操作后的数独状态中。

  5. 查询整个数独的状态,你需要使用方阵格式将整个数独目前的状态输出。
    方阵格式是一个19×19的二维字符数组,具体格式如下,其中用0 表示
    该位置还未填入数字。
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |5|7|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|7|1|0|0|0|
    ±±±±±±±±±+
    |0|0|0|0|0|0|0|0|0|
    ±±±±±±±±±+
    |9|8|7|6|5|4|3|2|1|
    ±±±±±±±±±+

输入格式
输入的前19行为一个二维字符数组,为数独的初始状态的方阵格式。
随后一行一个整数T 表示操作的次数。
随后T 行,每行为下列形式:
Insert x y k ,表示在(x, y)位置插入数k。
Delete x y,表示删除(x, y)位置的数。
Query x y ,表示查询(x, y)位置能填入且不会出现冲突的数。
Merge i j ,表示合并第i 次操作后的状态和第j 次操作后的状态。
Print ,表示查询整个数独的状态。
其中x 表示行数,从上到下分别为1 到9,y 表示列数,从左到右分别为1
到9。

虽然看着特别多,但其实特别水,模拟即可。

思路:

插入

首先要判断是否合法。
很简单,首先枚举这一行是否有等于的,再枚举这一列,最后枚举3*3的九宫格。
这里我使用的是找到每个九宫格的中心,然后枚举该点到哪个点的距离最小即属于这个九宫格。距离这里使用的曼哈顿距离即可。

每个中心的位置。打表即可。

int p[10]={
    
    0,2,5,8,2,5,8,2,5,8};
int q[10]={
    
    0,2,2,2,5,5,5,8,8,8};

找到最小的距离的,即属于这个九宫格。

for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) Min=abs(x-q[i])+abs(y-p[i]),r=i;
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			if(a[i][j]==k) {
    
    cout<<"Error:square!"<<endl;cpy();return;}

查询

判断合法和插入差不多。
仅需将枚举的点放到桶里,标记一下,最后扫一遍即可。

inline void query(int x,int y)
{
    
    
	memset(tong,0,sizeof(tong));
	if(a[x][y])
	{
    
    	
		cout<<"Error!"<<endl;
		cpy();
		return;
	}
	for(int i=1;i<=9;i++)
		tong[a[x][i]]=1;
	for(int i=1;i<=9;i++)
		tong[a[i][y]]=1;
	int Min=0x3f3f3f3f;
	for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) Min=abs(x-q[i])+abs(y-p[i]),r=i;
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			tong[a[i][j]]=1;
	
	int sum=0;
	for(int i=1;i<=9;i++)
		if(!tong[i]) sum++;
	cout<<sum<<endl;
	for(int i=1;i<=9;i++)
		if(!tong[i]) cout<<i<<endl;
	cpy();
}

警告:桶要初始化,桶要初始化。

删除和输出

非常水,不需要多说了吧。

合并

其实也很简单。
每次操作我们都存下来了,直接枚举,判断是否合法就可以了。

inline bool check(int k,int x,int y)
{
    
    
	for(int i=1;i<=9;i++)
		if(a[x][i]==k) return 0;
	for(int i=1;i<=x;i++)
		if(a[i][y]==k) return 0;
	int Min=0x3f3f3f3f;
	for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) {
    
    Min=abs(x-q[i])+abs(y-p[i]);r=i;}
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			if(a[i][j]==k) return 0;
	return 1;
}

inline void Merge(int x,int y)
{
    
    
	memset(a,0,sizeof(a));
	int sum1=0,sum2=0;
	for(int i=1;i<=9;i++)
		for(int j=1;j<=9;j++)
		{
    
    
			if(tmp[x][i][j] && check(tmp[x][i][j],i,j)) {
    
    a[i][j]=tmp[x][i][j];sum1++;continue;}
			if(tmp[y][i][j] && check(tmp[y][i][j],i,j)) {
    
    a[i][j]=tmp[y][i][j];sum2++;continue;}
		}
	cout<<sum1<<" "<<sum2<<endl;
	cpy();
}

a也要初始化!!!
总代码:

#include<bits/stdc++.h>
using namespace std;

#define qwq ch-'0'
void get(int &res)
{
    
    
    char ch;bool flag=0;
    while(!isdigit(ch=getchar()))
        (ch=='-')&&(flag=true);
    for(res=qwq;isdigit(ch=getchar());res=res*10+qwq);
    	(flag)&&(res=-res);
}

const int N=105;
int t,a[N][N],r;
int p[10]={
    
    0,2,5,8,2,5,8,2,5,8};
int q[10]={
    
    0,2,2,2,5,5,5,8,8,8};
int tmp[205][20][20];
int cnt;
bool tong[N];

inline void cpy()
{
    
    
	++cnt;
	for(int i=1;i<=9;i++)
		for(int j=1;j<=9;j++)
			tmp[cnt][i][j]=a[i][j];
}

inline void Insert(int x,int y,int k)
{
    
    
	if(a[x][y]) {
    
    cout<<"Error!"<<endl;cpy();return;}
	for(int i=1;i<=9;i++)
		if(a[x][i]==k) {
    
    cout<<"Error:row!"<<endl;cpy();return;}
	for(int i=1;i<=9;i++)
		if(a[i][y]==k) {
    
    cout<<"Error:column!"<<endl;cpy();return;}
	int Min=0x3f3f3f3f;
	for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) Min=abs(x-q[i])+abs(y-p[i]),r=i;
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			if(a[i][j]==k) {
    
    cout<<"Error:square!"<<endl;cpy();return;}
	cout<<"OK!"<<endl;
	a[x][y]=k;
	cpy();
}

inline void Delete(int x,int y)
{
    
    
	if(a[x][y]==0) cout<<"Error!"<<endl;
	else 
		cout<<"OK!"<<endl;a[x][y]=0;
	cpy();
}

inline void query(int x,int y)
{
    
    
	memset(tong,0,sizeof(tong));
	if(a[x][y])
	{
    
    	
		cout<<"Error!"<<endl;
		cpy();
		return;
	}
	for(int i=1;i<=9;i++)
		tong[a[x][i]]=1;
	for(int i=1;i<=9;i++)
		tong[a[i][y]]=1;
	int Min=0x3f3f3f3f;
	for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) Min=abs(x-q[i])+abs(y-p[i]),r=i;
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			tong[a[i][j]]=1;
	
	int sum=0;
	for(int i=1;i<=9;i++)
		if(!tong[i]) sum++;
	cout<<sum<<endl;
	for(int i=1;i<=9;i++)
		if(!tong[i]) cout<<i<<endl;
	cpy();
}

inline void Print()
{
    
    
	printf("+-+-+-+-+-+-+-+-+-+\n");
	for(int i=1;i<=9;i++)
	{
    
    
		for(int j=1;j<=9;j++) printf("|%d",a[i][j]);
		printf("|\n");
		printf("+-+-+-+-+-+-+-+-+-+\n");
	}
	
	cpy();
}

inline bool check(int k,int x,int y)
{
    
    
	for(int i=1;i<=9;i++)
		if(a[x][i]==k) return 0;
	for(int i=1;i<=x;i++)
		if(a[i][y]==k) return 0;
	int Min=0x3f3f3f3f;
	for(int i=1;i<=9;i++)
		if(abs(x-q[i])+abs(y-p[i])<Min) {
    
    Min=abs(x-q[i])+abs(y-p[i]);r=i;}
	for(int i=q[r]-1;i<=q[r]+1;i++)
		for(int j=p[r]-1;j<=p[r]+1;j++)
			if(a[i][j]==k) return 0;
	return 1;
}

inline void Merge(int x,int y)
{
    
    
	memset(a,0,sizeof(a));
	int sum1=0,sum2=0;
	for(int i=1;i<=9;i++)
		for(int j=1;j<=9;j++)
		{
    
    
			if(tmp[x][i][j] && check(tmp[x][i][j],i,j)) {
    
    a[i][j]=tmp[x][i][j];sum1++;continue;}
			if(tmp[y][i][j] && check(tmp[y][i][j],i,j)) {
    
    a[i][j]=tmp[y][i][j];sum2++;continue;}
		}
	cout<<sum1<<" "<<sum2<<endl;
	cpy();
}

int main()
{
    
    
//	freopen("sudoku.in","r",stdin);
//	freopen("sudoku.out","w",stdout);
	char s;int cnt1=1,cnt2=0;
	for(int i=1;i<=19;i++)
		for(int j=1;j<=19;j++)
		{
    
    
			cin>>s;
			if(s>='0' && s<='9')
			{
    
    
				cnt2++;
				if(cnt2>9) cnt1++,cnt2=1;
				a[cnt1][cnt2]=s-'0';
			}
		}
	    
	string str;
	int x,y,k;
	get(t);
	while(t--)
	{
    
    
		cin>>str;
		if(str[0]=='I') 
		{
    
    
			get(x);get(y);get(k);
			Insert(x,y,k);
		}
		if(str[0]=='D')
		{
    
    
			get(x);get(y);
			Delete(x,y);
		}
		if(str[0]=='Q')
		{
    
    
			get(x);get(y);
			query(x,y);
		}
		if(str[0]=='P')
		{
    
    
			Print();
		}
		if(str[0]=='M')
		{
    
    
			get(x);get(y);
			Merge(x,y);
		}
	}
	return 0;
}

告诫大家:
在这里插入图片描述sizeof(tong) 才是对的。

猜你喜欢

转载自blog.csdn.net/pigonered/article/details/121103561