#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
/**
Problem : UVA11205 - The broken pedometer
Begin Time: 28th/Mar/2012 11:30 a.m.
Finish Time: 29th/Mar/2012 2:14 a.m.
Last Time : About 6 hours.
State:9924407 11205 The broken pedometer Accepted C++ 2.684 2012-03-28 18:11:32
Knowledge : BFS,剪枝都没有,还有子集生成,也算有个小小的状态压缩?
Exp.: WA * 4 :这四个Wrong Answer奉献给了误把BFS写成DFS,不应该
WA * 4 :我他妈对于后四个WA无力吐槽了啊我操。边界,边界!
tmp.depth + 1 <= col写成了 tmp.depth + 1 < col结果就少了一组组合啊!过脑子啊白痴!写程序时。
操操操操操。
Thought:
每行换成10110101这样的整数(因为最多才2^15,不用位运算了,否则怪麻烦的)
开一个数组isSel[],如果ith列被选了那么isSel[i] = true;
然后根据isSel判断目前选的列数,以及应该从那几列中抽取子集。
其实位运算能快一些。
Summerize:
发现搜索出错的时候
1.仔细想一下搜索的过程,状态转移的方式,是否有状态结点未展开
2.想一下边界,是否有问题
最重要的,写之前看清楚了,一般有最短,最少,最小字样的统统为BFS.
搜索的如果是个树,则不需要回溯,如果是个图,则需要回溯。
*/
const int MAXN = 200;
const int MAXP = 50;
int puzzle[MAXN][MAXP];
int subset[MAXN];
bool isSel[MAXN];
int minN;
bool isFound;
struct node
{
int depth;
bool isSel[MAXN];
};
node tmp;
queue<node> que;
int comp(const void *a, const void *b)
{
return (*(int*)a - *(int*)b);
}
bool check(int row,int col)
{
int cnt = 0;
memset(subset,0,sizeof(subset));
for(int i = 0 ; i < col ; i++)
{
if(isSel[i] == true)
cnt++;
}
for(int j = 0 ; j < row ; j++)
{
for(int i = 0 ; i < col ; i++)
{
if(isSel[i] == true )
{
subset[j] = subset[j] * 10 + puzzle[j][i];
}
}
}
qsort(subset,row,sizeof(int),comp);
int i = 0;
int j = i+1;
while( j < row )
{
if(subset[i] == subset[j])
{
return false;
}
i++,j++;
}
if( minN > cnt)
{
minN = cnt;
}
return true;
}
int Solve(int row,int col,int now)
{
node tmp,tmp1,k;
while(!que.empty())
{
tmp=que.front();
que.pop();
memcpy(isSel,tmp.isSel,sizeof(isSel));
tmp1 = tmp;
check(row,col);
if(tmp.depth + 1 <= col)
{
tmp1.depth = tmp.depth + 1;
tmp1.isSel[tmp1.depth - 1] = false;
que.push(tmp1);
tmp1.isSel[tmp1.depth - 1] = true;
que.push(tmp1);
}
}
return minN;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("b:\\acm\\UVA\\UVA11205\\input.txt","r",stdin);
freopen("b:\\acm\\uva\\uva11205\\output.txt","w",stdout);
#endif
int T,P,N,k;
// while( scanf("%d",&T) != EOF )
scanf("%d",&T);
{
for(int t = 1 ; t <= T ; t++)
{
scanf("%d%d",&P,&N);
memset(puzzle,0,sizeof(puzzle));
memset(subset,0,sizeof(subset));
memset(isSel,0,sizeof(isSel));
for(int i = 0 ; i < N ; i++)
{
for(int j = 0 ; j < P ; j++)
{
scanf("%d",&puzzle[i][j]);
}
}
minN = 200;
tmp.depth = 1;
tmp.isSel[0] = true;
que.push(tmp);
tmp.depth = 1;
tmp.isSel[0] = false;
que.push(tmp);
k = Solve(N,P,0);
printf("%d\n",k);
while(!que.empty())
{
que.pop();
}
}
}
return 0;
}