CodePlus 第五次网络赛 我有矩阵,你有吗?(思维题)

题目描述

企鹅豆豆手里有两个 01 矩阵 A 和 B 。他可以进行两种操作:

  1. 选择 A 矩阵的一行,然后把这一行的 0 变成 1 ,把 1 变成 0 。
  2. 选择 A 矩阵的一列,然后把这一列的 0 变成 1 ,把 1 变成 0 。

现在他想知道能不能把 A 矩阵通过以上操作变成 B 矩阵。保证 A 矩阵和 B 矩阵的大小一致。

输入格式

从标准输入读入数据。

每个测试点只有一组数据。

输入的第一行包含两个正整数 n 和 m ,表示 A 矩阵的行数,保证 n≤103 ,m≤103 。 接下来 n 行,每行 m 个由空格隔开的整数,表示矩阵 A 。保证矩阵中只有 0 或者 1 。 接下来 n 行,每行 m 个由空格隔开的整数,表示矩阵 B 。保证矩阵中只有 0 或者 1 。

输出格式

输出到标准输出。

如果矩阵 A 通过以上两种操作可以变成矩阵 B ,输出 Koyi,否则输出 Budexing

样例1输入

3 3
1 0 1
1 1 0
0 1 0
1 1 0
0 1 0
1 1 0

样例1输出

Koyi

 

 解析:

虽然是一道很简单的题目,但我太菜了,想了一个多小时才想出来...所以记录一下自己和大佬的做法

首先都是先处理出差别的矩阵dif,a,b不相同的位置标1,

我的想法是第一行都用列解决。如果第一行有差异的位置,那么就把对应这一列都变一次。

然后剩下的2-n行,再用行解决,如果剩下的2-n行,还有差异的,那把这一行都变一次。

这样无论是怎么的变换,都可以通过我这种方法转换到。

因为如果需要列变换的,我一定是有的。剩下的就是不需要列变换,只需要变换第一行,那么我再把下面的行都进行

行变换补回来就可以了。另外一种情况就是正解1:第一行变换,加上几个列变换,那么用我这种方法,就刚刚好

把正解1里面没有列变换的那几列变换了,有变换的列没有变换。但是这个你试一下就知道,可以互相转换的。

只要n-2行你加行变换就可以等价转换成正解1了。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = 1e3+100;
int a[MAXN][MAXN];
int row[MAXN];
int col[MAXN];
int vis[MAXN];

int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int tmp;
			scanf("%d",&tmp);
			a[i][j]^=tmp;
		}
	}


	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j])
			{
				row[i]++;
				col[j]++;

			}
		}
	}
	for(int j=1;j<=m;j++)
	{
		if(a[1][j])
		{
			for(int k=1;k<=n;k++)
			{
				a[k][j]^=1;

			}
		}
	}
	for(int i=2;i<=n;i++)
	{
		if(a[i][1])
		{
			for(int j=1;j<=m;j++)
				a[i][j]^=1;
		}
	}
	int flag=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j]==1)
			{
				flag=0;
				break;
			}
		}
		if(!flag) break;
	}
	if(flag) printf("Koyi\n");
	else printf("Budexing\n");
		
}

下面是大佬1的做法,对于dif的每一行,最多只可能有2种状态。无论有没有进行列变换,dif矩阵进行行变换的和没有行变换的行。那么进行行变换的行,对应那一行的dif的值一定是相同的。同理没有进行行变换的也应该是相同的。

那么我们只需要记录这两个状态就好了。列同理

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1010;
int a[N][N],n,m,can;
int main(){
	cin>>n>>m;
	for (int i=1;i<=n;i++)
	for (int j=1;j<=m;j++)scanf("%d",&a[i][j]);
	for (int i=1;i<=n;i++)
	for (int j=1;j<=m;j++){
		int x;
		scanf("%d",&x);
		a[i][j]^=x;
	}
	can=1;
	int std1=-1,std2=-1;
	for (int i=1;i<=n;i++){
		int cnt=0;
		for (int j=1;j<=m;j++)cnt+=a[i][j];
		if (cnt==std1||cnt==std2)continue;
		if (std1==-1){
			std1=cnt;
			continue;
		}
		if (std2==-1){
			std2=cnt;
			continue;
		}
		can=0;
	}std1=-1;std2=-1;
	for (int i=1;i<=m;i++){
		int cnt=0;
		for (int j=1;j<=n;j++)cnt+=a[j][i];		
		if (cnt==std1||cnt==std2)continue;
		if (std1==-1){
			std1=cnt;
			continue;
		}
		if (std2==-1){
			std2=cnt;
			continue;
		}
		can=0;
	}
	printf(can?"Koyi\n":"Budexing\n");
}

大佬2:大佬2是使用了并查集。如果dif矩阵中为1的行i和列j,就加入一个并查集。处理之后,dif[i][j]=0的行i和列j 一定不在一个并查集里面,这个自己举几个例子就知道了。

/*
Author: CNYALI_LK
LANG: C++
PROG: A.cpp
Mail: cnyalilk@vip.qq.com
*/
#include<bits/stdc++.h>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define Debug debug("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#define all(x) x.begin(),x.end()
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1.0);
template<class T>int chkmin(T &a,T b){return a>b?a=b,1:0;}
template<class T>int chkmax(T &a,T b){return a<b?a=b,1:0;}
template<class T>T sqr(T a){return a*a;}
template<class T>T mmin(T a,T b){return a<b?a:b;}
template<class T>T mmax(T a,T b){return a>b?a:b;}
template<class T>T aabs(T a){return a<0?-a:a;}
template<class T>int dcmp(T a,T b){return a>b;}
template<int *a>int cmp_a(int x,int y){return a[x]<a[y];}
#define min mmin
#define max mmax
#define abs aabs
namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	// getchar
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	// print the remaining part
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	// putchar
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	// input a signed integer
	inline void read (int &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
	}
	inline void read (char &x) {
		x=gc();
	}
	inline void read(char *x){
		while((*x=gc())=='\n' || *x==' '||*x=='\r');
		while(!(*x=='\n'||*x==' '||*x=='\r'))*(++x)=gc();
	}
	template<typename A,typename ...B>
	inline void read(A &x,B &...y){
		read(x);read(y...);
	}
	// print a signed integer
	inline void write (int x) {
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
	inline void write (char x) {
		putc(x);
	}
	inline void write(const char *x){
		while(*x){putc(*x);++x;}
	}
	inline void write(char *x){
		while(*x){putc(*x);++x;}
	}
	template<typename A,typename ...B>
	inline void write(A x,B ...y){
		write(x);write(y...);
	}
	//no need to call flush at the end manually!
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: read;
using io :: putc;
using io :: write;
int a[1023][1023],fa[2047];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
#ifdef cnyali_lk
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
#endif
	int n,m,x;
	//read(n,m);
	cin>>n>>m;
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)cin>>a[i][j];
	for(int i=1;i<=n+m;++i)fa[i]=i;
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){cin>>x;a[i][j]^=x;if(a[i][j])fa[find(i)]=find(j+n);}
	for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)if(!a[i][j] && find(i)==find(j+n))return printf("Budexing\n"),0;
	printf("Koyi\n");


	return 0;
}

大佬3:大佬3的想法跟我是差不多的,只是他没有把变换更新到矩阵里面,而是存在s1,s2里面

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int n,m;
int s[1005][1005],t[1005][1005];
int s1[1005],s2[1005];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&s[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&t[i][j]);
	s1[0]=0;
	for(int i=1;i<=m;i++)
		s2[i]=s[1][i]^t[1][i];
	for(int i=1;i<=n;i++)
		s1[i]=s2[1]^s[i][1]^t[i][1];
	int fl=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if((s1[i]^s2[j])!=(s[i][j]^t[i][j])) fl=1;
		}
	if(fl) puts("Budexing");
	else puts("Koyi");
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值