/* 很大的教训 最小路径覆盖首先是每个点拆点的问题 接着这个题目对于某一行来说,只需要找到比它大的行就可以了,不要既找到比它小的,又找到比它大的,这样会导致重复连边 思考,对于每个点,只要找到比它大的,用一条路径覆盖,就是从小到大,这样就可以了 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int usedif[110]; int lin[110]; bool mat[110][110]; int gx,gy,m; struct shu { int num[110]; } map[110]; bool can(int t) { for(int i=1; i<=gy; i++) { if(usedif[i]==0&&mat[t][i]) { usedif[i]=1; if(lin[i]==-1||can(lin[i])) { lin[i]=t; return true; } } } return false; } int MaxMatch() { int num=0; memset(lin,-1,sizeof(lin)); for(int i=1; i<=gx; i++) { memset(usedif,0,sizeof(usedif)); if(can(i)) num++; } return num; } int main() { int T; int cas=1; scanf("%d",&T); while(T--) { memset(mat,false,sizeof(mat)); int n; scanf("%d%d",&n,&m); gx=n; gy=n; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%d",&map[i].num[j]); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { bool flag=false; for(int k=1; k<=m; k++) if(map[i].num[k]<=map[j].num[k]) { flag=true; break; } if(!flag) { mat[i][j]=1; } } } int t=MaxMatch(); printf("Case #%d: %d/n",cas++,n-t); } return 0; }