본문 바로가기

삼성전자 알고리즘/정올

15. 3203 : 꿀벌의 여행

DFS문제 

1) 생각할 문제 

-패턴의 시작 위치를 어떻게 결정할 것인가?

-패턴의 시작 위치가 결정되었다면 각 벌들은 패턴의 어느 위치로 이동시킬 것인가?

-이동하는 과정에서 동시에 같은 위치로 이동하게 되면 어떻게 처리할 것인가?

 

2) 시작 위치의 결정

-시작 위치로 결정할 수 있는 범위 (0,0) ~ ( 100 - height, 100 - width )

-위의 범위 중 꿀벌의 위치와 전혀 겹치지 않는 곳은 최적의 결과가 나올 수 없다.

-모든 위치에 대해 최대 이동 꿀벌의 이동거리가 최소인 점을 찾는다.

패턴 범위 지정시 벌에 하나라도 겹치는 것이 유리하다.

 

가장 멀리 가는 벌이 총 이동 시간의 기준이 됨.

 

꽃과 벌이 매칭 가능한 경우의 수 = 7! (5040) 테스트케이스에 따라 부담스러울 수 있는 범위임.

 

백트래킹 기법 사용 필요 : 최소값으로 가지치기. 효율적으로 가지치는 법 : (그림 참조)

이러면 최소값 3이 나오고 3보다 큰 값들은 넘어간다.(가지치기 당함)

 

user.cpp

/// *** user.cpp area start ***

#define MAXBEE     7
#define MAXSIZE  100


// 아래 구조체 선언부는 채점시 주석처리 하고 제출해 주시기 바랍니다.
struct COORD {
	int y, x;
};

COORD start, mybee[MAXBEE], pt[MAXBEE], bs, be, target[MAXBEE];	//리턴값, 꿀벌위치, 패턴위치, 꿀벌의 시작과 끝 좌표, 목표 위치

int N, ansd; //최소이동거리
int order[MAXBEE], num[MAXBEE], chk[MAXBEE];
int map[100][100], dir[7];
const int yy[5] = { 0,0,1,0,-1 };
const int xx[5] = { 0,1,0,-1,0 };
																
/// *** submit area start***

extern int moveBee(int direction[MAXBEE]);
int Min(int x, int y) { return x < y ? x : y; }
int Max(int x, int y) { return x > y ? x : y; }
int Abs(int x) { return x < 0 ? -x : x; }
void init(int B, COORD bee[MAXBEE]) {
	N = B;
	bs.y = bs.x = 100;
	be.y = be.x = 0;
	for (int i = 0; i < N; i++) {
		mybee[i] = bee[i];
		bs.x = Min(bs.x, bee[i].x), be.x = Max(be.x, bee[i].x);
		bs.y = Min(bs.y, bee[i].y), be.y = Max(be.y, bee[i].y);
	}
}
void dfs(int sy, int sx, int n, int maxd) {
	if (maxd >= ansd) return;	//가지치기
	int i, k;
	if (n >= N) {
		ansd = maxd, start.y = sy, start.x = sx;
		for (i = 0; i < N; i++) {
			order[i] = num[i];
		}
	}
	for (i = 0; i < N; i++) {
		if (chk[i]) continue;
		chk[i] = 1;
		num[n] = i;
		k = Abs(pt[i].y + sy - mybee[n].y) + Abs(pt[i].x + sx-mybee[n].x);
		dfs(sy, sx, n + 1, Max(maxd, k));
		chk[i] = 0;
	}

}

void setting(int h, int w) {
	int i, j, k, sy, sx, ey, ex;
	sy = (bs.y + (be.y - h)) / 2, sx = (bs.x + (be.x - w)) / 2;	//중심을 기준으로 하기. 확률적으로 최소값일 확률 높음
	if (sy < 0) { sy = 0; } if (sy > 100 - h) { sy = 100 - h; }
	if (sx < 0) { sx = 0; } if (sx > 100 - w) { sx = 100 - w; }
	for (k = 0; k < N; k++) { chk[k] = 0; }
	dfs(sy, sx, 0, 0);

	sy = Max(0, bs.y - h + 1), sx = Max(0, bs.x - w + 1);
	ey = Min(MAXSIZE - h, be.y), ex = Min(MAXSIZE - w, be.x);

	for (i = sy; i <= ey; i++) {
		for (j = sx; j <= ex; j++) {
			for (k = 0; k < N; k++) {
				chk[k] = 0;
			}
			dfs(i, j, 0, 0);
		}
	}
}
int move(int k) {
	int i, j, flag = 0, ny, nx;
	for (i = 0; i < N; i++) {
		dir[i] = 0;
		for (j = 1; j <= 4; j++) {
			ny = mybee[i].y + yy[i], nx = mybee[i].x + xx[i];
			if (Abs(target[i].y - mybee[i].y) < Abs(target[i].y - ny)) continue;
			if (Abs(target[i].x - mybee[i].x) < Abs(target[i].x - nx)) continue;
			if (map[ny][nx] = k) continue;
			map[ny][nx] = k;
			dir[i] = j;
			mybee[i].y = ny, mybee[i].x = nx;
			flag = 1;
			break;
		}
	}
	return flag;
}
COORD make_pattern(int H, int W, int pattern[MAXSIZE][MAXSIZE]) {
	COORD  result;
	int i, j, k = 0;
	for (i = 0; i < 100; i++) {
		for (j = 0; j < 100; j++) {
			map[i][j] = 0;
		}
	}
	for (i = 0; i < H; i++) {
		for (j = 0; j < W; j++) {
			if (pattern[i][j]) {
				pt[k].y = i;
				pt[k].x = j;
				k++;
			}
		}
	}
	ansd = 10000;	//넉넉한 값
	setting(H, W);
	for (i = 0; i < N; i++) {
		target[i].y = pt[order[i]].y + start.y;
		target[i].x = pt[order[i]].x + start.x;
	}
	for (k = 1; move(k); k++) {
		moveBee(dir);
	}
	bs = be = start;
	be.y += H - 1, be.x += W - 1;
	return start;
}

 

main.cpp

/// *** main.cpp ***
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif

#include  <stdio.h >

#define MAXBEE             7
#define MAXSIZE          100
#define MAXMOVECOUNT   100000 
static const double ratio = 2.0; // it will be changed

struct COORD {
	int y, x;
};

static COORD bee[MAXBEE];
static int pattern[MAXSIZE][MAXSIZE];
static int width, height, N, M;

static bool okay;
static int movecnt, moveCntLimit;
static int score;
static const int dy[5] = { 0, 0, 1, 0, -1 };
static const int dx[5] = { 0, 1, 0, -1, 0 };

extern void init(int N, COORD bee[MAXBEE]);
extern COORD make_pattern(int height, int width, int pattern[MAXSIZE][MAXSIZE]);

int moveBee(int dir[MAXBEE]) {
	if (!score)
		return score;

	movecnt++;

	if (movecnt > MAXMOVECOUNT)
		return score = 0;

	for (int i = 0; i < N; ++i) {
		if (dir[i] < 0 || dir[i] > 4) {
			return score = 0;
		}

		bee[i].y += dy[dir[i]];
		bee[i].x += dx[dir[i]];

		if (bee[i].y < 0 || bee[i].y >= MAXSIZE || bee[i].x < 0 || bee[i].x >= MAXSIZE)
			return score = 0;
	}

	for (int i = 0; i < N; ++i) {
		for (int j = i + 1; j < N; ++j)
			if (dir[i] * dir[j] > 0 && bee[i].y == bee[j].y && bee[i].x == bee[j].x)
				return score = 0;
	}

	return 1;
}

static bool Matched(COORD start) {
	for (int i = 0; i < N; ++i) {
		int y = bee[i].y - start.y;
		int x = bee[i].x - start.x;

		if (y < 0 || y >= height || x < 0 || x >= width || pattern[y][x] == 0)
			return false;
		--pattern[y][x];
	}
	return true;
}

static void play() {
	scanf("%d %d", &N, &M);
	for (int i = 0; i < N; ++i)
		scanf("%d %d", &bee[i].y, &bee[i].x);

	init(N, bee);

	movecnt = 0;

	for (int i = 0; i < M; ++i) {

		int flower_pattern[MAXSIZE][MAXSIZE] = { { 0 } };

		scanf("%d %d %d", &height, &width, &moveCntLimit);
		for (int y = 0; y < height; ++y) {
			for (int x = 0; x < width; ++x) {
				scanf("%d", &pattern[y][x]);
				flower_pattern[y][x] = pattern[y][x];
			}
		}
		int estimate = movecnt + moveCntLimit * ratio;

		COORD patten_start = make_pattern(height, width, flower_pattern);

		if (movecnt > estimate || !Matched(patten_start))
			score = 0;
		if (score == 0) return;
	}
}

int main() {
	// freopen("input.txt", "r", stdin);
	int T;
	scanf("%d", &T);
	int totalscore = 0;
	for (int t = 1; t <= T; ++t) {
		score = 100;
		play();
		if (score == 0) {
			totalscore = 0;
			break;
		}
		printf("#%d : %d \n", t, movecnt);
		totalscore += score;
	}
	printf("\nscore = %d\n", totalscore);
	return 0;
}

'삼성전자 알고리즘 > 정올' 카테고리의 다른 글

3240 : 회원 참여도 분석1  (0) 2019.07.27
16. 3181 : 족보 만들기  (0) 2019.07.24
14. 1133 : Uniqueness  (0) 2019.06.28
13. 1726 : 구간의 최대값1  (0) 2019.06.28
12. 1141 : 불쾌한 날  (0) 2019.06.28