import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
class Solution {
static int knum, depth, Width;
static int[][] data;
static boolean Converse;
private static int Result;
private static boolean Debug = false;
public static void main(String args[]) throws Exception {
BufferedReader br;
br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int TestNo = Integer.parseInt(br.readLine());
for (int T = 1; T <= TestNo; T++) {
st = new StringTokenizer(br.readLine());
// 문제 읽기
depth = Integer.parseInt(st.nextToken());
Width = Integer.parseInt(st.nextToken());
knum = Integer.parseInt(st.nextToken());
data = new int[depth][];
// 데이터 읽기
for (int i = 0; i < depth; i++) {
data[i] = new int[Width];
st = new StringTokenizer(br.readLine());
for (int j = 0; j < Width; j++) {
data[i][j] = Integer.parseInt(st.nextToken());
}
}
Result = -1;
if (isOkay()) { // 원형 그대로 두어도 Okay
Result = 0;
}
for (int i = 1; i <= knum; i++) { // i개의 행에 약물 주입
if (Result >= 0) {
break; // 찾았으면 종료
}
visitingList = new ArrayList<>(); // 중복검색 방지
possibleList = new ArrayList<Integer>(); // 1이 i개인 이진수 탐색
int con_i = i > Width / 2 ? Width - i : i;
Converse = i > Width / 2;
findPossible(con_i, 0); // 1이 i개인 이진수 탐색
for (int j = 0; j < possibleList.size(); j++) {
log(Integer.toBinaryString(possibleList.get(j)));
Result = inputMedi(possibleList.get(j)); // (약물 주입) 행들의 집합을 넘긴다.
if (Result > 0) {
break; // 찾았으면 종료
}
}
}
System.out.println(String.format("#%d %d", T, Result));
}
}
static ArrayList<Integer> possibleList;
static ArrayList<Integer> visitingList;
// width개 중 i개를 선택한다.
private static void findPossible(int i, int bitinfo) {
if (bitinfo >= (1 << depth + 1)) {
return;
}
int count = 0;
for (int j = 0; j < depth; j++) {
if ((bitinfo & (1 << j)) > 0) {
count++;
if (count == i) {
log(Integer.toBinaryString(bitinfo));
possibleList.add(bitinfo);
return;
}
}
}
for (int j = 0; j < depth; j++) {
if ((bitinfo & (1 << j)) > 0) {
continue;
}
int next_bitinfo = bitinfo + (1 << j);
if (visitingList.contains(next_bitinfo)) {
continue;
}
visitingList.add(next_bitinfo);
findPossible(i, next_bitinfo);
}
}
public static int inputMedi(int selbit) {
ArrayList<Integer> pocket = new ArrayList<Integer>();
// 사용되는 열 추출
int con_selbit = selbit;
if (Converse) {
con_selbit = 0;
for (int i = 0; i < Width; i++) {
if ((selbit & (1 << i)) == 0) {
con_selbit += (1 << i);
}
}
}
for (int i = 0; i < Width; i++) {
if ((con_selbit & (1 << i)) > 0) {
pocket.add(i);
}
}
// boolean isFound;
int size = pocket.size();
// 1,0의 적용의 경우의 수
for (int i = 0; i < 1 << size; i++) {
// log(Integer.toBinaryString(i));
if (isOkay(i, pocket)) {
return pocket.size();
}
}
return -1;
}
private static boolean isOkay(int bitmask, ArrayList<Integer> pocket) {
int depth = data.length;
int width = data[0].length;
int a_count;
int b_count;
for (int i = 0; i < width; i++) {
a_count = b_count = 0;
int atom;
for (int j = 0; j < depth; j++) { // 한 열을 검사
atom = data[j][i];
if (pocket.indexOf(j) >= 0) {
boolean isOne = (bitmask & (1 << pocket.indexOf(j))) > 0;
atom = isOne ? 1 : 0;
}
if (atom == 1) {
if (b_count != 0) {
a_count = b_count = 0;
}
a_count++;
} else {
if (a_count != 0) {
a_count = b_count = 0;
}
b_count++;
}
if (a_count == knum || b_count == knum) {
break;
}
if (j == depth - 1) {
return false;
}
}
}
log(Integer.toBinaryString(bitmask) + pocket.toString());
return true;
}
private static boolean isOkay() {
int depth = data.length;
int width = data[0].length;
int a_count;
int b_count;
for (int i = 0; i < width; i++) {
a_count = b_count = 0;
for (int j = 0; j < depth; j++) { // 한 열을 검사
if (data[j][i] == 1) {
if (b_count != 0) {
a_count = b_count = 0;
}
a_count++;
} else {
if (a_count != 0) {
a_count = b_count = 0;
}
b_count++;
}
if (a_count == knum || b_count == knum) {
break;
}
if (j == depth - 1) {
return false;
}
}
}
return true;
}
private static void log(String input) {
if (Debug) {
System.out.println(input);
}
}
}
'Knowledge > 알고리즘' 카테고리의 다른 글
1952. [모의 SW 역량테스트] 수영장 (0) | 2017.10.07 |
---|---|
[와우패스] 동서남북 복불복 (0) | 2017.10.05 |
1849. 영준이의 무게측정 [Fail : 오답] (0) | 2017.10.04 |
1167.백준 트리의 지름 (시간초과...) (0) | 2017.10.01 |
11725.백준 트리의 부모 찾기 (0) | 2017.10.01 |