暴力枚举所有的子集列,比较在每种情况下每行是否唯一,我把每行数据当成2进制转化为10进制之后比较的。这里枚举子集是用的位向量法,产生的子集序列 子集大小变化是不规则的,但是一旦有小的子集可以区分所有行,子集大的情况就不用计算了,直接可以忽略。
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int led[105][20];
int flag[20];
int p, n;
int minNum;
void judge() {
int arr[105];
int idx = 0;
int setSize = 0;
int i, j;
for (i = 0; i < p; i++) {
if (flag[i]) {
setSize++;
}
}
/*子集列超过当前最小值,直接忽略*/
if (setSize >= minNum)
return;
/*每一行2进制数据根据子集列转化成十进制,如果有相同的则失败返回。*/
for (i = 0; i < n; i++) {
int curNum = 0;
for (j = 0; j < p; j++) {
if (flag[j] && led[i][j]) {
curNum += pow(2, j);
}
}
for (j = 0; j < idx; j++) {
if (arr[j] == curNum) {
return;
}
}
arr[idx++] = curNum;
}
/*没有返回表明没有相同的行*/
if (setSize < minNum)
minNum = setSize;
return;
}
/*递归生成子集列,在子集列中判断*/
void subSet(int cur) {
if (cur == p) {
judge();
return;
}
flag[cur] = 0;
subSet(cur + 1);
flag[cur] = 1;
subSet(cur + 1);
}
int findMinNum() {
minNum = p;
subSet(0);
return minNum;
}
int main() {
int cases;
scanf("%d", &cases);
while (cases--) {
scanf("%d%d", &p, &n);
int i, j;
for (i = 0; i < n; i++)
for (j = 0; j < p; j++)
scanf("%d", &led[i][j]);
printf("%d\n", findMinNum());
}
return 0;
}