求可区分出所有行的最小列数,用位向量法生成子集,然后枚举最小子集。最需要注意的是其0与1之间可能不止一个空格,开始用char型数组 scanf("%c%c", &a[i][j], &c); 读取的,因为这个WA了好几次,如果直接用int型数组求则可以省去很多麻烦。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
char b[101][17];
int a[101][17], flag[17], _min;
int subset(int n, int p, int cur)
{
if(cur == p)
{
int ct = 0;
for(int i = 0; i < p; i++)
if(flag[i])
{
for(int j = 0; j < n; j++)
b[j][ct] = a[j][i] + '0';
++ct;
}
for(int i = 0; i < n; i++)
b[i][ct] = 0;
for(int i = 0; i < n - 1; i++)
for(int j = i + 1; j < n; j++) // 所有子集应都不相同才可区分
if(!strcmp(b[i], b[j]))
return 0;
if(_min > ct)
_min = ct;
return 1;
}
flag[cur] = 0;
subset(n, p, cur + 1);
flag[cur] = 1;
subset(n, p, cur + 1);
return 0;
}
int main()
{
#ifdef test
freopen("in.txt", "r", stdin);
#endif
int t, p, n, ct;
scanf("%d", &t);
while(t--)
{
memset(flag, 0, sizeof(flag));
scanf("%d%d", &p, &n);
getchar();
for(int i = 0; i < n; i++)
for(int j = 0; j < p; j++)
scanf("%d", &a[i][j]);
_min = p;
ct = subset(n, p, 0);
printf("%d\n", _min);
}
return 0;
}