QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#691195#2943. NeighborsnickbelovAC ✓23ms1860kbC1118.3kb2024-10-31 10:21:162024-10-31 10:21:18

Judging History

你现在查看的是最新测评结果

  • [2024-10-31 10:21:18]
  • 评测
  • 测评结果:AC
  • 用时:23ms
  • 内存:1860kb
  • [2024-10-31 10:21:16]
  • 提交

answer

/*
 * Neighbors - GNY Regional 2021 - Fred Pickel
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>

//#define DEBUG
//#define FIND_ALL
//#define ONE_SHOT

typedef unsigned short WORD;
typedef unsigned char BYTE;
char inbuf[256];

int nVals;
int  initCnt;
/*
 * this is a standard recursive sudoku solver with two additions
 * 1. An initial scan of the sum constraints to see if they restrict the
 *		available values in each box (check_constraints)
 * 2. at each recursive search step, once we have set a value in a row & col
 *		and used sudoku constrints to remove available values in the row, col and 3x3 box
 *		scan through the sum constraints to see if they further restrict the
 *		available values in each box (check_constraints)
 */

int constraints[32][16];

WORD valid_masks[17] = 
	{0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
		0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000};
WORD allMasks[17] = 
{
	0, 0x0001, 0x0003, 0x0007, 0x000f,
		0x001f, 0x003f, 0x007f, 0x00ff,
		0x01ff, 0x03ff, 0x07ff, 0x0fff,
		0x1fff, 0x3fff, 0x7fff, 0xffff,
};

#define ALL_MASK	(allMasks[nVals])

/* flags for whether difference is neighbor or not */
WORD nbrDiff[17] =
{
	0, 0x0002, 0x0005, 0x000a, 0x0014, 0x0028, 0x0050, 0x00a0, 0x0140,
		0x0280,  0x0500, 0x0a00, 0x1400, 0x2800, 0x005000, 0xa000, 0x4000
}; 

WORD nonnbrDiff[17] =
{
	0, 0xfffc, 0xfff8, 0xfff1, 0xffe3, 0xffc7, 0xff8f, 0xff1f, 0xfe3f,
		0xfc7f, 0xf8ff, 0xf1ff, 0xe3ff, 0xc7ff, 0x8fff, 0x1fff, 0x3fff
}; 

/*
 * depth first search stack struct for sudoku
 */
typedef struct _search_state_
{
	WORD avail_mask[16][16];	// which values (valid_masks) can still be used in thsi box
	BYTE row_avail_counts[19][16];	// for each row, counts of how many boxes in the row have each value available
	BYTE col_avail_counts[16][16];	// for each col, counts of how many boxes in the col have each value available
	BYTE val_set[16][16];	// if non-zero, this box is set t the current value in the current search
} SEARCH_STATE;

SEARCH_STATE states[256];

/*
 * intialize the search stack to no values chosen and all values available
 * in all boxes
 */
void search_init()
{
	SEARCH_STATE *pss = &(states[0]);
	int i, j;
	for(i = 0; i < nVals; i++) {
		for(j = 0; j < nVals ; j++) {
			pss->avail_mask[i][j] = ALL_MASK;
			pss->val_set[i][j] = 0;
			pss->row_avail_counts[i][j] = nVals;
			pss->col_avail_counts[i][j] = nVals;
		}
	}
}

/*
 * convert string of 0, or 1 to array of 0 or 1
 */
int scan_convert(int *prow, int n, const char *s)
{
	int i;

	for(i = 0; i < n; i++, s++){
		switch(*s){
		case '0': *prow++ = 0; break;
		case '1': *prow++ = 1; break;
		default: return(i);
		}
	}
	return(i);
}

// read constraints from stdin
int scan_constraints()
{
	int i, j, n;
	for(i = 0, j = 0; i < nVals; i++) {
		if(fgets(&(inbuf[0]), 255, stdin) == NULL)
		{
			fprintf(stderr, "Read of row %d constraints failed\n", i+1);
			return -21;
		}
		n = scan_convert(&(constraints[j][0]), nVals - 1, &(inbuf[0]));
		if(n != nVals-1){
			fprintf(stderr, "Scan of row %d constraints failed got %d wanted %d: %s", i+1, n, nVals - 1, &(inbuf[0]));
			return(-22);
		}
		j++;
		if(i < nVals-1) {
			if(fgets(&(inbuf[0]), 255, stdin) == NULL)
			{
				fprintf(stderr, "Read of constraints between %d and %d failed\n", i+1, i+2);
				return -23;
			}
			n = scan_convert(&(constraints[j][0]), nVals, &(inbuf[0]));
			if(n != nVals) {
				fprintf(stderr, "Scan of constraints between %d and %d faile got %d wanted %d: %s\n", i+1, i+2, n, nVals, &(inbuf[0]));
				return -24;
			}
			j++;
		}
	}
	return 0;
}

/*
 * determine if any values available in the current box (baseMask) can
 * be excluded by applying constraint with the available values in the neighboring box (chkMask)
 * return mask of values to be REMOVED
 */
WORD checkConstraint(int constraint, WORD baseMask, WORD chkMask)
{
	WORD *pTest, result = 0;
	int i;
	if(constraint == 0) {
		pTest = &(nonnbrDiff[0]);
	} else if(constraint == 1) {
		pTest = &(nbrDiff[0]);
	}
	// if a val is avail but cannot match nbr flag as not useable
	for(i = 1; i <= nVals ; i++) {
		if(((valid_masks[i] & baseMask) != 0) && ((pTest[i] & chkMask) == 0)) {
			result |= valid_masks[i];
		}
	}
	return result;
}

/*
 * for each box, check if constraints with respect to neighboring boxes eliminate
 * any available values
 * return -1 if some box has no remaining available values
 */
int check_constraints(SEARCH_STATE *pss)
{
	int i, row, col, baseConsRow, scan_count, change_count = 1;
	WORD baseMask, chkMask, resultMask, totResult;
	scan_count = 0;
	// scan all constraints until no more changes
	while(change_count > 0) {
		scan_count++;
		change_count = 0;
		baseConsRow = 0;
		for(row = 0; row < nVals ; row++) {
			for(col = 0 ; col < nVals ; col++) {
				if(pss->val_set[row][col] == 0) {	// if we have not already set this box in search see if it can change
					baseMask = pss->avail_mask[row][col];
					totResult = 0;	// all changes to baseMask
					if(col != 0) {	// if not first col check constraint with box to left
						chkMask = pss->avail_mask[row][col-1];
						resultMask = checkConstraint(constraints[baseConsRow][col-1], baseMask, chkMask);
						if(resultMask != 0) {
							baseMask &= ~resultMask;
							change_count++;
							totResult |= resultMask;
						}
					}
					if(col < (nVals - 1)) {
						// do col to right
						chkMask = pss->avail_mask[row][col+1];
						resultMask = checkConstraint(constraints[baseConsRow][col], baseMask, chkMask);
						if(resultMask != 0) {
							baseMask &= ~resultMask;
							change_count++;
							totResult |= resultMask;
						}
					}
					if(row != 0) {	// if not top row, check constraint with row above
						chkMask = pss->avail_mask[row-1][col];
						resultMask = checkConstraint(constraints[baseConsRow-1][col], baseMask, chkMask);
						if(resultMask != 0) {
							baseMask &= ~resultMask;
							change_count++;
							totResult |= resultMask;
						}
					}
					if(row != (nVals - 1)) {	// if not bottom row, check constraint with box below
						chkMask = pss->avail_mask[row+1][col];
						resultMask = checkConstraint(constraints[baseConsRow+1][col], baseMask, chkMask);
						if(resultMask != 0) {
							baseMask &= ~resultMask;
							change_count++;
							totResult |= resultMask;
						}
					}
					if(baseMask == 0) {	// not already set and no values available for box
						return -1;
					}
					pss->avail_mask[row][col] = baseMask; 
					if(totResult != 0) {	// adjust counts for boxes in same row, col or 3x3 box
						for(i = 1; i <= nVals ; i++) {
							if(valid_masks[i] & totResult) {
								pss->col_avail_counts[col][i-1]--;
								pss->row_avail_counts[row][i-1]--;
							}
						}
					}
				}
			}
			baseConsRow += 2;
		}
	}
	return 0;
}

/*
 * depth first search step choice info
 */
#define STYP_ROW	1	// depth first search on boxes with a value available in a given row
#define STYP_COL	2	// depth first search on boxes with a value available in a given col
#define STYP_BOX	3	// depth first search on boxes with a value available in a given 3x3 box
typedef struct _solve_data_ {
	int solve_type;	//STYP_?
	int solve_val;	// value to be set 1-9
	int solve_row;	// row for row scan (0-8) or box row (0-2) for box unused for col
	int solve_col;	// col for col scan (0-8) or box col (0-2) for box unused for row
	int solve_cnt;	// number of boxes in set with val available
	int solve_index;	// which of solve_cnt boxes we are trying (init 0)
	int test_row;	// actual row and col to set to val
	int test_col;
} SOLVE_DATA;

/*
 * choose how to branch for the next sudoku depth first search step
 * choose the branching with the smallest number of children in the tree
 * either the sammlest number of values still available in a box (row & col)
 * or the smallest number of boxes in a row, col or 3x3 sub-box with a particular value available
 * on return *psd has the information on the branch choice
 */
int GetSolveStep(SEARCH_STATE *pss, SOLVE_DATA *psd)
{
	int i, j;
	psd->solve_cnt = nVals+1;
	for(i = 0; i < nVals; i++) {
		for(j = 0; j < nVals; j++) {
			if(pss->row_avail_counts[i][j] < psd->solve_cnt) {
				psd->solve_cnt = pss->row_avail_counts[i][j];
				psd->solve_type = STYP_ROW;
				psd->solve_row = i;
				psd->solve_val = j+1;
			}
		}
	}
	for(i = 0; i < nVals; i++) {
		for(j = 0; j < nVals; j++) {
			if(pss->col_avail_counts[i][j] < psd->solve_cnt) {
				psd->solve_cnt = pss->col_avail_counts[i][j];
				psd->solve_type = STYP_COL;
				psd->solve_col = i;
				psd->solve_val = j+1;
			}
		}
	}
	if(psd->solve_cnt == 0) {	// if some value has no choices left, fail
		return -1;
	} else {
		return 0;
	}
}

/*
 * after we have made a branch choice, we have to try each of the branches
 * at the search node bay scanning through boxes in the selected row, col or 3x3 box
 * or values within a selected box, thsi routine steps to the next choice
 * for first try, start with 0, else start with location after previous try
 * and scan to the next available box or value
 */
int FindNextTest(SEARCH_STATE *pss, SOLVE_DATA *psd)
{
	int i, j, starti, startj;
	WORD mask = valid_masks[psd->solve_val];
	if(psd->solve_index >= psd->solve_cnt) {
		return -1;
	}
	switch(psd->solve_type) {
	case STYP_ROW:
		if(psd->solve_index == 0) {
			startj = 0;
		} else {
			startj = psd->test_col+1;
		}
		i = psd->solve_row;
		for(j = startj ; j < nVals ; j++) {
			if(pss->avail_mask[i][j] & mask) {
				psd->test_col = j;
				psd->test_row = i;
				psd->solve_index++;
				return 0;
			}
		}
		return -1;
	case STYP_COL:
		if(psd->solve_index == 0) {
			starti = 0;
		} else {
			starti = psd->test_row+1;
		}
		j = psd->solve_col;
		for(i = starti ; i < nVals ; i++) {
			if(pss->avail_mask[i][j] & mask) {
				psd->test_col = j;
				psd->test_row = i;
				psd->solve_index++;
				return 0;
			}
		}
		return -1;
	default:
		fprintf(stderr, "bad solve type %d\n", psd->solve_type);
		return -1;
	}
}

/*
 * apply a choice to set a box at row, col,to value
 * then clear all other avail masks at row, col and
 * apply sudoku constraints to decrement counts
 * for other boxes in row, col and 3x3 box not already set,
 * remove val from avail_masks and decrement counts
 */
int ApplyChoice(SEARCH_STATE *pss, int row, int col, int val)
{
	int i, j;
	WORD mask = valid_masks[val];
	if(pss->val_set[row][col] != 0) {
		fprintf(stderr, "ApplyChoice: row %d col %d val %d already set to %d\n", row, col, val, pss->val_set[row][col]);
		return -1;
	}
	pss->val_set[row][col] = val;
	// remove val from other avails in row, col and box
	for(j = 0; j < nVals ; j++) {
		if(pss->avail_mask[row][j] & mask) {	// reduce counts
			pss->col_avail_counts[j][val-1]--;
		}
		pss->avail_mask[row][j] &= ~mask;
	}
	for(i = 0; i < nVals ; i++) {
		if(pss->avail_mask[i][col] & mask) {
			pss->row_avail_counts[i][val-1]--;
		}
		pss->avail_mask[i][col] &= ~mask;
	}
	//for each other value at row/col, decrement ist counts
	for(i = 1; i <= nVals ; i++) {
		if((i != val) && ((pss->avail_mask[row][col] & valid_masks[i]) != 0)){
			pss->col_avail_counts[col][i-1]--;
			pss->row_avail_counts[row][i-1]--;
		}
	}
	pss->avail_mask[row][col] = mask;	// no one can use it but we need to tell neighbors that other vals not avail
	pss->row_avail_counts[row][val-1] = 64;	// never choose the row and val again
	pss->col_avail_counts[col][val-1] = 64;	// never choose the col and val again
	return 0;
}

#ifdef DEBUG
// This is a hack used to find an error
// it tests the sample solution against the current avail_masks
// to see if it could still be found
// this will fail during search when you go down the wrong path
// but should work on the solution path
int soln[7][7] =
{
	{3, 5, 6, 1, 2, 7, 4},
	{2, 7, 5, 4, 6, 1, 3},
	{4, 6, 1, 3, 7, 5, 2},
	{7, 2, 4, 5, 3, 6, 1},
	{6, 4, 3, 7, 1, 2, 5},
	{5, 1, 2, 6, 4, 3, 7},
	{1, 3, 7, 2, 5, 4, 6}

};

int check_soln(SEARCH_STATE *pss)
{
	int i, j, ret = 0;
	for(i = 0; i < nVals; i++) {
		for(j = 0; j < nVals ; j++) {
			if((pss->avail_mask[i][j] & valid_masks[soln[i][j]]) == 0) {
				printf("mismatch at row %d col %d\n", i, j);
				ret = -1;
			}
		}
	}
	return ret;
}
#endif

int solnCnt = 0;

void PrintSoln(SEARCH_STATE *pss)
{
	int i, j;
	printf("%d\n", solnCnt);
	for(i = 0; i < nVals ; i++) {
		for(j = 0; j < nVals ; j++) {
			printf("%d ", pss->val_set[i][j]);
		}
		printf("\n");
	}
}

/*
 * sudoku recursive step
 * at given level, copy current state to next slot, 
 * pick a branch row col or 3x3 box and value
 * if we are down the last choice (depth = 80) just set the (only remaining) choice and return 0
 * for each branch. set the value at the row & col to the appropriate value
 * and update avail counts to reflect sudoku constraints
 * then chack sum constraints
 * if any box has no more available values, go on to the next choice on the branch
 * else call Solve recursively
 * If the recursive call returns -1, go on to the next choice on the branch
 *  and if you run out of boxes return -1
 * if recursive call returns 0, copy soln (val_set from next slot to current and return 0
 * so when top level returns, val_set is the soln
 */
int Solve(int level)
{
	SEARCH_STATE *pssnxt, *pss = &(states[level]);
	SOLVE_DATA sd;
	int i, j;
	if(GetSolveStep(pss, &sd) != 0) {	// find row, col or 3x3 box) + value to scan
		return -1;
	}
#ifdef DEBUG
	printf("level %d solve type %d row %d col %d val %d cnt %d\n", level,
		sd.solve_type, sd.solve_row, sd.solve_col, sd.solve_val, sd.solve_cnt);
#endif
	sd.solve_index = 0;
	while(FindNextTest(pss, &sd) == 0) {	// for each candidate in chosen row, col or 3x3 box, get row& col to set
		if(level == nVals*nVals - initCnt - 1) {	// if this is the last box to fill in we are done, set it and return 0 (success)
			pss->val_set[sd.test_row][sd.test_col] = sd.solve_val;
#ifdef FIND_ALL
			solnCnt++;
			PrintSoln(pss);
			return -1;
#else
			return 0;
#endif
		} else {	// else copy current to next and try each possiblility
			pssnxt = &(states[level+1]);
			*pssnxt = *pss;
#ifdef DEBUG
			fprintf(stderr, "try row %d col %d val %d\n", sd.test_row, sd.test_col, sd.solve_val);
#endif
			if(ApplyChoice(pssnxt, sd.test_row, sd.test_col, sd.solve_val) == 0) { // set this value choice
#ifdef DEBUG
				check_soln(pssnxt);
#endif
				if(check_constraints(pssnxt) == 0) {	// if not killed by constraints	
#ifdef DEBUG
					check_soln(pssnxt);
#endif
					if(Solve(level+1) == 0) {	// call solve recursively, if success, copy val_set
						for(i = 0; i < nVals; i++) {
							for(j = 0; j < nVals ; j++) {
								pss->val_set[i][j] = pssnxt->val_set[i][j];
							}
						}
						return 0;
					}
				}
#ifdef DEBUG
			} else {
				fprintf(stderr, "Apply Choice failed at level %d \n", level);
#endif
			}
		}
	}
	return -1;
}

int main()
{
	int ret, i, row, col, val;
#ifndef FIND_ALL
	int j;
#endif
#ifdef ONE_SHOT
	int nprob, curprob, index;
	if(fgets(&(inbuf[0]), 255, stdin) == NULL)
	{
		fprintf(stderr, "Read failed on problem count\n");
		return -1;
	}
	if(sscanf(&(inbuf[0]), "%d", &nprob) != 1)
	{
		fprintf(stderr, "Scan failed on problem count\n");
		return -2;
	}
	for(curprob = 1; curprob <= nprob ; curprob++)
	{
		if(fgets(&(inbuf[0]), 255, stdin) == NULL)
		{
			fprintf(stderr, "Read failed on problem %d header\n", curprob);
			return -3;
		}
		// get prob num degree
		if(sscanf(&(inbuf[0]), "%d %d", &index, &i) != 2)
		{
			fprintf(stderr, "scan failed on problem header problem index %d\n",
				curprob);
			return -4;
		}
		if(index != curprob)
		{
			fprintf(stderr, "problem index %d not = expected problem %d\n",
				index, curprob);
			return -5;
		}
#endif
		if(fgets(&(inbuf[0]), 255, stdin) == NULL)
		{
			fprintf(stderr, "Read failed on initCnt\n");
			return -6;
		}
		// get initCnt and nVals
		if(sscanf(&(inbuf[0]), "%d %d", &nVals, &initCnt) != 2)
		{
			fprintf(stderr, "scan failed on nVals + initCnt\n");
			return -7;
		}
		if((nVals < 4) || (nVals > 16)) {
			fprintf(stderr, "nVals  %d not in range 4 .. 16\n",
				nVals);
			return -8;
		}
		if((initCnt < 0) || (initCnt > (nVals*nVals))) {
			fprintf(stderr, "init val cnt %d not in range 0 .. %d1\n",
				initCnt, nVals*nVals);
			return -8;
		}
		search_init();	// init first atate
		if((ret = scan_constraints()) != 0) {	// read constriants
			return ret;
		}
		if(check_constraints(&(states[0])) != 0) { // apply constraints to first state
			fprintf(stderr, "init check constraints failed\n");
			return -8;
		}
		for(i = 0; i < initCnt ; i++) {
			if(fgets(&(inbuf[0]), 255, stdin) == NULL)
			{
				fprintf(stderr, "Read failed on init val %d\n", i+1);
				return -9;
			}
			// get prob num degree
			if(sscanf(&(inbuf[0]), "%d %d %d", &row, &col, &val) != 3)
			{
				fprintf(stderr, "scan failed on init val %d\n", i+1);
				return -10;
			}
			if((row < 1) || (row > nVals) || (col < 1) || (col > nVals) || (val < 1) || (val > nVals)) {
				fprintf(stderr, "init val %d row %d col %d or val %d not in range 1 .. %d\n",
					i+1, row, col, val, nVals);
				return -11;
			}
			if(ApplyChoice(&(states[0]), row-1, col-1, val) != 0) {
				fprintf(stderr, "init val %d error adding row %d col %d or val %d\n",
					i+1, row, col, val);
				return -12;
			}
			if(check_constraints(&(states[0])) != 0) { // apply constraints to first state
				fprintf(stderr, "check constraints failed after init val %d\n",
					i+1);
				return -13;
			}
		}
#ifdef DEBUG
		if(check_soln(&(states[0])) != 0) {
			fprintf(stderr, "problem index %d after init check constraints no match\n",
				index);
			return -18;
		}
#endif
		solnCnt = 0;
#ifdef FIND_ALL
#ifdef ONE_SHOT
		printf("%d\n", index);
#endif
		Solve(0); 	// call solve
		if(solnCnt == 0) {
			fprintf(stderr, "no solution\n");
			return -39;
		}
#else
		if(Solve(0) != 0) {
			printf("no solutions\n");
			return -21;
		}
		// if it works, print out soln
#ifdef ONE_SHOT
		printf("%d\n", index);
#endif
		for(i = 0; i < nVals ; i++) {
			for(j = 0; j < nVals ; j++) {
				printf("%d ", states[0].val_set[i][j]);
			}
			printf("\n");
		}
#endif
#ifdef ONE_SHOT
	}
#endif
	return 0;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 0ms
memory: 1768kb

input:

7 6
100000
0111010
100000
0000000
001001
0010010
000000
0000000
000000
0000000
001000
0001010
000001
2 7 7
6 1 2
3 3 2
7 6 2
5 3 6
4 7 6

output:

4 3 5 7 1 6 2 
1 2 4 6 3 5 7 
7 5 2 1 6 3 4 
3 7 1 5 2 4 6 
5 1 6 2 4 7 3 
2 6 3 4 7 1 5 
6 4 7 3 5 2 1 

result:

ok 7 lines

Test #2:

score: 0
Accepted
time: 0ms
memory: 1680kb

input:

7 6
100011
0010000
000001
1101010
010010
0111100
010000
0001000
011011
0001000
010101
0100000
000010
4 3 2
4 5 7
1 2 6
5 4 5
2 4 2
5 1 1

output:

5 6 4 7 1 2 3 
3 1 5 2 4 6 7 
4 2 1 3 6 7 5 
6 3 2 4 7 5 1 
1 7 6 5 2 3 4 
7 4 3 6 5 1 2 
2 5 7 1 3 4 6 

result:

ok 7 lines

Test #3:

score: 0
Accepted
time: 0ms
memory: 1656kb

input:

8 9
0001000
10110100
1000000
00001110
0001001
10100011
0000101
00000100
0101001
10000000
0000000
00100101
0010001
00100000
0000010
3 5 3
4 1 7
6 8 6
4 5 1
1 4 7
1 3 5
1 5 6
3 6 6
6 2 8

output:

4 2 5 7 6 8 1 3 
5 6 4 8 2 7 3 1 
8 1 7 2 3 6 4 5 
7 3 8 6 1 2 5 4 
2 5 6 3 4 1 7 8 
1 8 3 5 7 4 2 6 
6 4 2 1 5 3 8 7 
3 7 1 4 8 5 6 2 

result:

ok 8 lines

Test #4:

score: 0
Accepted
time: 0ms
memory: 1720kb

input:

9 9
00000100
010001001
01010010
010000010
00100101
100000010
10100010
010000100
01000001
100000000
00000000
010100000
10010100
000010100
00101000
110100000
00001000
3 5 6
4 2 1
7 1 4
2 2 6
6 9 1
5 7 4
3 1 1
4 3 5
9 4 4

output:

3 5 2 7 1 9 8 6 4 
9 6 7 3 4 8 1 2 5 
1 7 9 8 6 4 5 3 2 
2 1 5 6 9 7 3 4 8 
8 2 3 9 5 1 4 7 6 
7 4 6 2 8 3 9 5 1 
4 3 8 1 2 5 6 9 7 
6 8 4 5 3 2 7 1 9 
5 9 1 4 7 6 2 8 3 

result:

ok 9 lines

Test #5:

score: 0
Accepted
time: 1ms
memory: 1716kb

input:

10 11
010000000
1000000000
010101011
0101000001
001001000
0100100000
101000000
0000000001
000001000
0000101010
000000000
0000000001
100000000
0001000000
000001001
1000110000
100000011
1100000011
111010101
5 8 3
9 1 7
3 8 4
3 4 3
10 6 9
4 9 2
6 3 4
2 3 5
1 2 2
8 4 9
2 5 1

output:

9 2 3 8 4 6 10 7 1 5 
10 6 5 2 1 4 3 9 8 7 
1 5 2 3 9 7 8 4 10 6 
3 4 7 6 8 1 5 10 2 9 
5 1 9 4 2 8 7 3 6 10 
2 9 4 7 3 10 6 8 5 1 
4 3 8 10 7 5 1 6 9 2 
6 10 1 9 5 3 4 2 7 8 
7 8 10 1 6 2 9 5 4 3 
8 7 6 5 10 9 2 1 3 4 

result:

ok 10 lines

Test #6:

score: 0
Accepted
time: 23ms
memory: 1860kb

input:

11 12
0000001101
00000001000
0011000000
00110000000
0010000010
00000110000
0000100000
00000001100
0000000000
01010000010
0000010000
00001010000
0000000101
00000010010
0100100000
00100000101
1000010100
00100001010
1001000000
00010001000
0000000000
8 7 7
8 9 1
10 11 9
6 5 10
9 2 8
1 10 8
4 6 6
2 4 10
...

output:

2 9 11 1 3 10 6 5 4 8 7 
5 7 9 10 11 2 4 6 8 3 1 
1 3 8 9 4 7 2 10 5 6 11 
4 10 1 5 7 6 3 8 11 9 2 
9 4 6 3 5 11 1 7 10 2 8 
3 5 2 4 10 8 9 11 7 1 6 
6 1 7 2 9 5 8 4 3 11 10 
11 6 5 8 2 3 7 9 1 10 4 
7 8 4 11 6 9 10 1 2 5 3 
10 11 3 7 8 1 5 2 6 4 9 
8 2 10 6 1 4 11 3 9 7 5 

result:

ok 11 lines

Test #7:

score: 0
Accepted
time: 0ms
memory: 1720kb

input:

4 3
000
0001
001
0010
010
0100
100
1 2 1
2 2 4
1 4 2

output:

3 1 4 2 
1 4 2 3 
4 2 3 1 
2 3 1 4 

result:

ok 4 lines

Test #8:

score: 0
Accepted
time: 0ms
memory: 1576kb

input:

5 3
1111
00110
1010
10010
0000
00110
0101
01001
0000
5 2 2
2 4 3
2 5 5

output:

5 4 3 2 1 
2 1 4 3 5 
3 5 1 4 2 
1 3 2 5 4 
4 2 5 1 3 

result:

ok 5 lines

Test #9:

score: 0
Accepted
time: 0ms
memory: 1624kb

input:

6 5
10000
000100
10110
110100
10000
010011
01000
001000
00100
001110
00101
6 5 2
5 6 5
3 6 2
4 3 2
5 4 4

output:

1 2 5 3 6 4 
4 5 1 2 3 6 
3 4 6 1 5 2 
5 3 2 6 4 1 
2 6 3 4 1 5 
6 1 4 5 2 3 

result:

ok 6 lines

Test #10:

score: 0
Accepted
time: 0ms
memory: 1600kb

input:

7 6
011101
0001001
000000
0000010
000010
0000100
001001
0010001
001000
0001000
100000
0000001
100100
3 7 1
4 4 1
7 3 4
2 1 4
3 3 6
6 2 3

output:

1 4 5 6 7 3 2 
4 6 1 7 2 5 3 
7 2 6 3 5 4 1 
3 5 2 1 4 7 6 
5 1 3 4 6 2 7 
2 3 7 5 1 6 4 
6 7 4 2 3 1 5 

result:

ok 7 lines

Test #11:

score: 0
Accepted
time: 0ms
memory: 1604kb

input:

8 9
0011000
00000010
1000000
01011000
0110000
10000000
1000010
00000010
1010101
10110010
0010000
00000001
0000000
11001010
0000000
5 2 1
8 8 1
7 2 2
4 5 5
7 6 1
3 3 3
3 4 2
6 3 6
8 7 5

output:

1 7 2 3 4 6 8 5 
4 5 8 1 6 2 7 3 
8 4 3 2 7 5 1 6 
7 6 1 8 5 3 4 2 
2 1 5 6 8 7 3 4 
3 8 6 5 1 4 2 7 
5 2 4 7 3 1 6 8 
6 3 7 4 2 8 5 1 

result:

ok 8 lines

Test #12:

score: 0
Accepted
time: 1ms
memory: 1712kb

input:

9 10
00010000
001000000
00010000
000001100
00001001
000100000
00100101
001000111
01001001
100000000
10000001
000100010
00110010
000000001
01010000
000000001
00000000
9 8 9
4 1 4
4 6 7
3 1 1
3 6 3
7 1 2
8 2 5
8 4 2
4 3 5
2 9 1

output:

9 4 8 1 2 6 3 7 5 
5 2 7 9 8 4 6 3 1 
1 6 2 7 4 3 5 8 9 
4 1 5 6 9 7 8 2 3 
7 3 4 8 6 5 9 1 2 
6 7 9 3 1 8 2 5 4 
2 9 3 4 5 1 7 6 8 
8 5 6 2 3 9 1 4 7 
3 8 1 5 7 2 4 9 6 

result:

ok 9 lines