算法训练-审美课

问题描述

        《审美的历程》课上有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。 

解题思路

        至目前为止,我仍有两个用例无法通过,运行超时。在写第一次的时候,我是用二维数组加类冒泡排序法比较学生们输入的答案是否完全不一致,但是循环嵌套太多,效率太慢,有三个用例无法通过;第二版改进版,我将二维数组合并为一维数组,即将011<逻辑上的二进制型>转换为6<十进制型>,通过十进制的异或运算和与运算,判断学生们的答案是否完全不一致。

        异或运算的思路:

            异或的规则是00 得0 ,11 得0 ,10 得1 ,01得1,因此当两个同学的答案完全相反时,得到的结果应该是二进制的全1,由于我是用十进制直接异或,所以可以利用异或结果和图片位数的1进行与运算来判断异或结果是否为全1。

             举例,当图片的个数为3时,假设异或结果为6,6--->110,111---->7,6&7的结果是6,两学生的答案不完全相反;假设两学生的答案完全相反,异或结果必为7,111---->7,7&7的结果是7,即111,以此类推,可以推导出两学生的答案是否完全相反。

第一版实现

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
	int students, pictures, i, j, z, count = 0;
	scanf("%d %d", &students, &pictures);
	int results[students][pictures];
	for (i = 0; i < students; i++) {
		for (j = 0; j < pictures; j++) {
			scanf("%d", &results[i][j]);
		}
	}
	for (i = 0; i < students - 1; i++) {
		for (j = i + 1; j < students; j++) {
			for (z = 0; z < pictures; z++) {
				if (results[i][z] == results[j][z]) {
					break;
				}
			}
			if (z == pictures) {
				count++;
			}
		}
	}
	printf("%d\t", count);
	return 0;
}

a4d5be28f0a89ed30ad8986612b23a32440.jpg

第二版实现

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[]) {
	// god用于存放十进制值,即假设pictures为3,二进制情况下为111,则god = 7
	int students, pictures, i, j, z, count = 0, god = 1;
	scanf("%d %d", &students, &pictures);
	int results[students][pictures];
	int staging[students];
	for (i = 0; i < students; i++) {
		for (j = 0; j < pictures; j++) {
			scanf("%d", &results[i][j]);
		}
	}
	for (i = 0; i < students; i++) {
		long long sum = 0;
		for (j = 0; j < pictures; j++) {
			sum += results[i][j] * pow(2, j);
		}
		staging[i] = sum;
	} 
	for (i = 1; i < pictures; i++) {
		god += pow(2, i);
	}
	// 使用异或运算和与运算判断两个学生的答案是否完全相反 
	for (i = 0; i < students - 1; i++) {
		for (j = i + 1; j < students; j++) {
			int sum1 = -1;
			sum1 = staging[i] ^ staging[j] & god;
			if (sum1 == god) {
				count++;
			}

		}
	}
	printf("%d\t", count);
	return 0;
}

016ec7cbe83f427989bcdb9f305f708bdba.jpg

转载于:https://my.oschina.net/niithub/blog/3020187

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值