uva 11205(枚举子集)

题意:给出一些二进制数,有n行p列,判断在p列中,最少几列就能区分这n行的二进制数,注意列数不一定连续。

题解:此题用到了枚举子集,n的子集有2^n - 1个子集,所以就将 0 到 2^n - 1每个数的二进制和给出的二进制按‘与’位运算符运算,如果得到的值未被标记就标记为1,如果已经标记过了,说明这种子集有重复,那么列数的最小值不会存在在这个子集中,否则将子集中的1的个数统计出来,每个子集都统计一次,最后个数最少的数就是最小列数。

#include <stdio.h>
#include <math.h>
#include <string.h>
const int N = 100 + 5;
const int MAX = 40000;
int p, n, s[N], vis[MAX], count, ans, a[N];
void init() {
	for (int i = 0; i < N; i++)
		s[i] = 0;
	for (int i = 0; i < MAX; i++)
		vis[i] = 0;
	ans = 16;
}
void subset(int j) {
	int temp, flag = 1;
	for (int i = 0; i < n; i++) {
		temp = s[i] & j; //取交集
		a[i] = temp;
		if (vis[temp]) {
			flag = 0;
			break;
		}
		else
			vis[temp] = 1;
	}
	if (flag) {
		count = 0;
		for (int i = 0; i < p; i++)
			if (j & 1 << i)
				count++; //统计1的个数
		if (count < ans)
			ans = count;
	}
	for (int i = 0; i < N; i++)
		vis[a[i]] = 0;
}
int main() {
	int cases, a;
	scanf("%d", &cases);
	while (cases--) {
		init();
		scanf("%d%d", &p, &n);	
		for (int i = 0; i < n; i++)
			for (int j = p - 1; j >= 0; j--) {
				scanf("%d", &a);
				s[i] += a * pow(2, j);
			}
		for (int i = 0; i < (1 << p); i++)
			subset(i);
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值