打卡信奥刷题(3578)用C++实现信奥题 P11476 [COCI 2024/2025 #3] 涂矩阵 / Bojanje

P11476 [COCI 2024/2025 #3] 涂矩阵 / Bojanje

题目背景

译自 COCI 2024/2025 #3 T3。 1s,0.5G \texttt{1s,0.5G} 1s,0.5G。满分为 90 90 90

题目描述

有一个初始为全白的 n × n n\times n n×n 矩阵。

每次操作可以选择一列 / 一行,将这一列 / 一行覆盖成红色 / 蓝色。

给定矩阵的目标状态,试构造一组操作序列使得矩阵达到目标状态,或者报告无解。

不需要最小化操作序列的长度,合法即可得分。

输入格式

第一行,一个正整数 n n n

接下来 n n n 行,每行 n n n 个正整数,第 i i i 行第 j j j 个整数 a i , j a_{i,j} ai,j 描述目标状态中第 i i i 行第 j j j 列格子的颜色: 0 0 0 表示白色, 1 1 1 表示红色, 2 2 2 表示蓝色。

输出格式

如果无解,输出 − 1 -1 1

否则,第一行输出一个整数 k k k,表示操作序列长度。你需要保证 0 ≤ k ≤ 4   000 0\le k\le 4\, 000 0k4000

接下来 k k k 行,每行三个正整数 a , b , c a,b,c a,b,c,依次描述操作:

  • a ∈ { 1 , 2 } a\in \{1,2\} a{1,2} a = 1 a=1 a=1 代表选择的是行, a = 2 a=2 a=2 代表选择的是列。
  • 1 ≤ b ≤ n 1\le b\le n 1bn:代表选择的是第 b b b 行(列)。
  • c ∈ { 1 , 2 } c\in \{1,2\} c{1,2}:代表涂的是什么颜色。 1 1 1 表示红色, 2 2 2 表示蓝色。

输入输出样例 #1

输入 #1

3
0 0 1
1 1 1
0 0 1

输出 #1

2
2 3 1
1 2 1

输入输出样例 #2

输入 #2

3
1 1 2
2 1 1
2 1 1

输出 #2

-1

输入输出样例 #3

输入 #3

4
0 1 2 1
2 2 2 1
0 1 2 1
1 1 2 1

输出 #3

5
2 2 1
1 2 2
2 4 1
1 4 1
2 3 2

说明/提示

对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 2 × 10 3 1\le n\le 2\times 10^3 1n2×103

子任务编号 k ≤ k\le k特殊性质得分
$ 1 $ 2 × 10 3 2\times 10^3 2×103A$ 15 $
$ 2 $ 10 2 10^2 102$ 35 $
$ 3 $ 2 × 10 3 2\times 10^3 2×103$ 40 $
  • 特殊性质 A: a i , j ∈ { 0 , 1 } a_{i,j}\in\{0,1\} ai,j{0,1}

C++实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct ans{int a,b,c;}ans[4005];
int n,a[2005][2005],w[3][2005],h[3][2005],cnt;
bool check(){
	bool flag=0;
	for(int i=1;i<=n;i++){
		if((w[1][i]>0&&w[2][i]==0||w[2][i]>0&&w[1][i]==0)&&w[0][i]==0||(h[1][i]>0
			&&h[2][i]==0||h[2][i]>0&&h[1][i]==0)&&h[0][i]==0)return 1;//有一列或有一行全是1或2,返回1继续删
		if(w[1][i]>0||w[2][i]>0||h[1][i]>0||h[2][i]>0)flag=1;
	}
	if(flag){
		cout<<-1;
		exit(0);
	}
	return 0;
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>a[i][j],w[a[i][j]][i]++,h[a[i][j]][j]++;//记录每一列和每一行0,1,2的个数
	while(check()){
		for(int i=1;i<=n;i++){//删行
			if(w[0][i]>0||w[1][i]>0&&w[2][i]>0)continue;//有0或者既有1又有2
			if(w[1][i]>0){//全是1
				ans[++cnt]={1,i,1},w[1][i]=0;
				for(int i=1;i<=n;i++)h[1][i]--;
			}
			if(w[2][i]>0){//全是2
				ans[++cnt]={1,i,2},w[2][i]=0;
				for(int i=1;i<=n;i++)h[2][i]--;
			}
		}
		for(int i=1;i<=n;i++){//删列
			if(h[0][i]>0||h[1][i]>0&&h[2][i]>0)continue;//有0或者既有1又有2
			if(h[1][i]>0){//全是1
				ans[++cnt]={2,i,1},h[1][i]=0;
				for(int i=1;i<=n;i++)w[1][i]--;
			}
			if(h[2][i]>0){//全是2
				ans[++cnt]={2,i,2},h[2][i]=0;
				for(int i=1;i<=n;i++)w[2][i]--;
			}
		}
	}
	cout<<cnt;
	for(int i=cnt;i>0;i--)cout<<"\n"<<ans[i].a<<" "<<ans[i].b<<" "<<ans[i].c;
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值