算法训练-审美课

13 篇文章 1 订阅

问题描述

《审美的历程》课上有n位学生,帅老师展示了m幅画,其中有些是梵高的作品,另外的都出自五岁小朋友之手。老师请同学们分辨哪些画的作者是梵高,但是老师自己并没有答案,因为这些画看上去都像是小朋友画的……老师只想知道,有多少对同学给出的答案完全相反,这样他就可以用这个数据去揭穿披着皇帝新衣的抽象艺术了(支持帅老师^_^)。
答案完全相反是指对每一幅画的判断都相反。

输入格式

第一行两个数n和m,表示学生数和图画数;
接下来是一个n*m的01矩阵A:
如果aij=0,表示学生i觉得第j幅画是小朋友画的;
如果aij=1,表示学生i觉得第j幅画是梵高画的。

输出格式

输出一个数ans:表示有多少对同学的答案完全相反。
--------------------- 

样例输入

3 2
1 0
0 1
1 0

样例输出

2

样例说明

  同学1和同学2的答案完全相反;
  同学2和同学3的答案完全相反;
  所以答案是2。

数据规模和约定

  对于50%的数据:n<=1000;
  对于80%的数据:n<=10000;
  对于100%的数据:n<=50000,m<=20。

对于这个问题:我们需要了解的知识点有哪些?关注点有哪些?又如何巧妙躲坑?

思路:首先观察题目输入给我们的信息,每个同学只会出现0,1这两种结果,好,我们看到1,0一定要有这样的觉悟:1,0是和二进制有关的内容;并且两位同学答案”完全相反“。“^”运算刚好满足我们的需求。

大致我们是向二进制靠近了。那么如何这些数存储起来?也就是说,我们要考虑输入数的存储方式。

这里有两种方案:

1.map<int , int> arr;  用map存数据,it->first表示每个同学二进制转化成十进制的数,it->second同样的数据有多少(用于计数)

2.map<vector<int>,int>;同样也是map存数据,不同的是,我们输入的数据不再进行处理,直接用一个数组存储vector<int>,换句话说,我们可以下标是一串序列的形式,得到相同序列的个数。

巧妙点:

1).C++中的可以关闭stdio;

IOS::sync_with_stdio(false);

2.使用map

其中值得注意的是:vector申明数组大小:vector<int>arr(m);m是数组的大小

上代码:

方法一:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
map <int,int> arr;

int main(){
	ios::sync_with_stdio(false);//cin与stdio默认是同步存在的,关闭后可提高运算速度 
	int n,m;
	int vl = 0;//存放输入的数据 
	int tmp;//计算每行的总和 
	
	cin>>n>>m;
	for(int i=0;i<n;i++){
		tmp=0;
		for(int j=0;j<m;j++){
			cin>>vl;
			tmp=(tmp<<1)+vl;//移位计算 ,注意<<的优先级低于+,一定要加括号 
		}
		arr[tmp]++;//每次有相同的就加+1 
	}
	int cnt=0;
	int sum=0;
	int Max = (1<<m)-1;//先求出最大值 
	int mid = Max/2;//因为map默认的是从小到大排序,我们仅需要对1/2个数据进行判断即可 

	for(map<int,int>::iterator it=arr.begin();it!=arr.end();it++){
		cnt = it->first;
		if(cnt>mid){
			break;
		}
		int y1 = cnt^Max;
		sum+=arr[y1]*it->second; 
	}
	cout<<sum<<endl;
	
} 

方法二:

#include<iostream>
#include<map>
#include<vector>
using namespace std;
map<vector<int>,int> arr;
int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	vector <int>tt(m);
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>tt[j];
		}
		arr[tt]++;
	}
	int sum = 0;
	map<vector<int>,int>::iterator it;
	for(it=arr.begin();it!=arr.end();it++){
	
		for(int i=0;i<m;i++){
			tt[i]=it->first[i]^1;
		} 
		sum+=arr[tt]*it->second;
	}
	cout<<sum/2<<endl;
	return 0;
} 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值