www.acmicpc.net/problem/17406

 

17406번: 배열 돌리기 4

크기가 N×M 크기인 배열 A가 있을때, 배열 A의 값은 각 행에 있는 모든 수의 합 중 최솟값을 의미한다. 배열 A가 아래와 같은 경우 1행의 합은 6, 2행의 합은 4, 3행의 합은 15이다. 따라서, 배열 A의

www.acmicpc.net

 

 

1. 풀이 방법

 

- 경우의 수는 명령의 순서에 따라 결과가 달라지므로 순열로 구했습니다.

 

 

- 회전을 구현해야 하는데, 바깥쪽 부터 한 겹씩 회전을 시키는 순으로 했고

=

  맨 안쪽에 남은 하나는 오른쪽으로 가려고 하는데 이미 방문한 곳이면 break 하게끔 하였습니다.

 

 

-코드가 많이 길어졌네요...ㅠ

 

 

 

 

2.주의할 점.

 

- 코드가 길어지다보니 처음 짠 부분에서 이곳 저곳에서 문제가 발생...

   디버깅을 한참했습니다...

 

 

-디버깅을 아예 안하기는 쉽지 않겠지만 처음 짤 때 그래도 좀 세심하게 해야겠네요...

 

 

-그리고 (r-s,r+s) 입력이 이런식 이기때문에 행과 열의 수는 모두 홀수 입니다.

(처음에 짝수 개도 되는 경우의 수도 생각하고 짰었는데...풀다보니 발견...)

 

 

- 조건에 따른 문제를 정확하게 파악해야겠습니다...

 

 

 

 

3. 나의코드

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int N, M;
int K,r,s;
int doublearr[51][51]; //본 2차원 배멸 (변화 x)
int caculdoublearr[51][51]; //case별 결과값을 뽑아내기 위한 배열
int copydoublearr[51][51]; //이동을 위해 값을 복사해놓을 임시배열
bool check[51][51];
bool selected[7];
vector<int> resultmin;

struct rcs {
	int r,c,s;
};
vector<rcs> command; //입력받은명령
vector<rcs> casecommand; // 각 경우의수 (시뮬레이션 돌릴)

void input() { // 입력받는 함수		
	cin >> N >> M >> K;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			cin >> doublearr[i][j];
		}
	}
	rcs tmp;
	for (int i = 0; i < K; i++) {
		cin >> tmp.r >> tmp.c >> tmp.s;
		command.push_back(tmp);
	}
}
void copyarr() { // 원본배열은 그대로 두고 복사해서 사용 (각 테스트케이스마다 써야하므로)
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			copydoublearr[i][j] = doublearr[i][j];
			caculdoublearr[i][j] = doublearr[i][j];
		}
	}
}
void initcheck() { // 방문배열 초기화
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			check[i][j] = false;
		}
	}
}
void copycal() { //한번회전한 배열을 계산을 위한 배열에 복사
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= M; j++) {
			copydoublearr[i][j] = caculdoublearr[i][j];
		}
	}
}
void turnarr(int r, int c, int s) { //회전을 구현
	int x = r - s;
	int y = c - s;
	int tmpcount = 0;
	int totalcount = 8 * s; //연산해야하는 횟수 한 바퀴에
	char dir = 'R';
	initcheck();
	while (1) {
		if (totalcount == tmpcount) { //바깥한바퀴 -> 안쪽 바퀴로 들어감
			x += 1; y += 1; s -= 1; totalcount = 8 * s;
			tmpcount = 0;
		}
		if (dir == 'R') {
			if (check[x][y+1] == true) { copycal(); break;
			}
			caculdoublearr[x][y + 1] = copydoublearr[x][y];
			tmpcount++;
			check[x][y] = true;
			y += 1;
			if (y == c + s) { dir = 'D'; }
		}
		else if (dir == 'D') {
			caculdoublearr[x + 1][y] = copydoublearr[x][y];
			tmpcount++;
			check[x][y] = true;
			x += 1;
			if (x == r + s) { dir = 'L'; }
		}
		else if (dir == 'L') {
			caculdoublearr[x][y - 1] = copydoublearr[x][y];
			tmpcount++;
			check[x][y] = true;
			y -= 1;
			if (y == c - s) { dir = 'U'; }
		}
		else {
			caculdoublearr[x - 1][y] = copydoublearr[x][y];
			tmpcount++;
			check[x][y] = true;
			x -= 1;
			if (x == r - s) { dir = 'R'; }
		}
	}
}
int getmin() { //배열의 최소값을 뽑아내는 함수
	int mini = 5001;
	for (int i = 1; i <= N; i++) {
		int tmpsum = 0;
		for (int j = 1; j <= M; j++) {
			tmpsum += caculdoublearr[i][j];
		}
		if (tmpsum < mini) { mini = tmpsum; }
	}
	return mini;
}
void relocating() { //명령을 수행 (회전명령)
	copyarr();
	for (int i = 0; i < K; i++) {
		turnarr(casecommand[i].r, casecommand[i].c, casecommand[i].s);
	}
	resultmin.push_back(getmin());
}
void simulation(int n) { //순열 경우의 수 생성
	if (n == K) {
		relocating(); 
		return;
	}
	for (int i = 0; i < command.size(); i++) {
		if (selected[i] == true) continue;
		selected[i] = true;
		casecommand.push_back(command[i]);
		simulation(n+1);
		casecommand.pop_back();
		selected[i] = false;
	}
}



int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL); cout.tie(NULL);
	input();
	simulation(0);
	sort(resultmin.begin(), resultmin.end());
	cout << resultmin[0];
	return 0;
}

'알고리즘 문제풀이 > 구현' 카테고리의 다른 글

백준 2033 C++  (0) 2020.11.25
백준 14890 [C++]  (0) 2020.10.21
백준 15686 [C++]  (0) 2020.10.17
백준 3190 [C++]  (0) 2020.10.17
백준 18406 [C++]  (0) 2020.10.16

www.acmicpc.net/problem/17070

 

17070번: 파이프 옮기기 1

유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의

www.acmicpc.net

- 완전탐색을 문제 조건에 맞게 구현하여 경우의 수를 구하면 되는 간단한 문제이다.

 

- CASE는 방법에 따른 이동을 순열로 구하면 되는데 현재 파이프가 어떻게 놓여져 있는 지 에 따라 사용 가능한 이동방법이 다르므로 그것만 분류해주면 된다.

 

-direction 은 0은 가로, 1은 세로 , 2는 대각선이고

 case 1~7의 경우 문제에 표기된 그림의 순서 그대로 사용하였다.

#include<iostream>
#include<vector>
using namespace std;

int totalcount=0;
int housemap[17][17];
int N;
int x=1;
int y=2;
int dx[3] = { 0,1,1 }; //가로,세로,대각선이동
int dy[3] = { 1,0,1 };
int direction = 0; // 가로,세로,대각선 방향
void startsearch(int x,int y,int d) {
	if (x > N || y > N) return; //종료조건(미도착)
	if (x == N && y == N) { totalcount++; return; } //종료조건(도착
	if (d == 0) {
		if (housemap[x + dx[0]][y + dy[0]] != 1) 
		startsearch(x + dx[0], y + dy[0], 0); //case 1
		if (housemap[x + dx[2]][y + dy[2]] != 1 && housemap[x + dx[1]][y + dy[1]] != 1 && housemap[x + dx[0]][y + dy[0]] != 1) 
		startsearch(x + dx[2], y + dy[2], 2); //case 2
	}
	else if (d == 1) {
		if (housemap[x + dx[1]][y + dy[1]] != 1) 
		startsearch(x + dx[1], y + dy[1], 1); //case 3
		if (housemap[x + dx[2]][y + dy[2]] != 1 && housemap[x + dx[1]][y + dy[1]] != 1 && housemap[x + dx[0]][y + dy[0]] != 1)
		startsearch(x + dx[2], y + dy[2], 2); //case 4
	}
	else {
		if (housemap[x + dx[0]][y + dy[0]] != 1)
		startsearch(x + dx[0], y + dy[0], 0); //case 5
		if (housemap[x + dx[1]][y + dy[1]] != 1) 
		startsearch(x + dx[1], y + dy[1], 1); //case 6
		if (housemap[x + dx[2]][y + dy[2]] != 1 && housemap[x + dx[1]][y + dy[1]] != 1 && housemap[x + dx[0]][y + dy[0]] != 1) 
		startsearch(x + dx[2], y + dy[2], 2); //case 7
	}
}

int main() {
	cin >> N;
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			cin >> housemap[i][j];
		}
	}
	if (housemap[N][N]!=1) { startsearch(x, y, direction); }
	cout << totalcount << "\n";
	return 0;
}

 

www.acmicpc.net/problem/17281

 

17281번: ⚾

⚾는 9명으로 이루어진 두 팀이 공격과 수비를 번갈아 하는 게임이다. 하나의 이닝은 공격과 수비로 이루어져 있고, 총 N이닝 동안 게임을 진행해야 한다. 한 이닝에 3아웃이 발생하면 이닝이 종�

www.acmicpc.net

- 모든 가능한 순열 case를 모두 구해서 야구 시뮬레이션을 돌려서 가장 큰 점수를 반환해주면 됩니다.

 

-순열 case만 제대로 모두 구한다면 야구게임 자체를 구현하는 것은 어렵지 않습니다.

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int N;
bool playerordercheck[10];
int playerresult[51][10];
int playerorder[10];
bool location[4]; //1루 2루 3루 를 표시
int resultscore;
int maxscore;
void input() {
	cin >> N;
	for (int i = 1; i <= N; i++) {
		for(int j=1;j<=9;j++){
			cin >> playerresult[i][j];
		}
	}
}
void resetlocation() { //1,2,3루 초기화
	for (int i = 1; i <= 3; i++) {
		location[i] = false;
	}
	return;
}
void getscorecheck(int num) {
	for (int i = 3; i >= 1; i--) {
		if (location[i] == true) {
			if (i + num >= 4) { location[i] = false; resultscore++; }
			else { location[i] = false; location[i + num] = true; } //주자 이동
		}
	}
	if (num >= 4) { resultscore++; return; } //홈런인 경우
	else { location[num] = true; return; }
}
int gamestart() {
	resultscore = 0;
	int outcount = 0;
	int playerpointer = 1;
	for (int i = 1; i <= N; i++) { //N이닝동안 반복
		outcount = 0; //이닝별 아웃카운터 초기화
		while (1) { //주자 한명씩 확인
			if (outcount == 3) {
				resetlocation(); //나가있던 주자들 모두 들어옴.
				break;
			}
			if (playerresult[i][playerorder[playerpointer]] == 1) { //1루타
				getscorecheck(1);
			}
			else if (playerresult[i][playerorder[playerpointer]] == 2) {//2루타
				getscorecheck(2);
			}
			else if (playerresult[i][playerorder[playerpointer]] == 3) {//3루타
				getscorecheck(3);
			}
			else if (playerresult[i][playerorder[playerpointer]] == 4) {//4루타
				getscorecheck(4);
			}
			else { //아웃된 경우
				outcount++;
			}
			playerpointer++;
			if (playerpointer == 10) { playerpointer = 1; } //9번 주자까지 다 치면 다시 1번 주자
		}
	}
	return resultscore;
}
void P(int cnt) {
	if (cnt == 10) {
		int tmp = gamestart();
		if (maxscore < tmp) { //각 case가 확정되면 게임을 시작한다.
			maxscore = tmp;
		} 
		return;
	}
	for (int i = 1; i <= 9; i++) {
		if (playerordercheck[i] == true) continue;//아직 배정되지 않은 선수라면playerordercheck[i] = true;
		playerordercheck[i] = true;
		playerorder[i] = cnt;
		P(cnt + 1); //모든 순열case을 찾자
		playerordercheck[i] = false;
	}
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	input();
	playerordercheck[4] = true; //4번타자는 1번으로 고정(문제조건) -이미 자리가 배정됨
	playerorder[4] = 1;
	P(2); //1명은 이미 자리 배정이 완료되었음으로... permutation(순열)
	      //순서를 고려해야함
	cout << maxscore << "\n";

	return 0;
}

1.개요

- 보이어모어 알고리즘 역시 kmp 알고리즘과 마찬가지로 패턴과 텍스트 중 패턴을 preprocessing 하는 방식이다.

- kmp 알고리즘과는 반대로 패턴을 텍스트의 특정 위치에 놓고 비교를 할 때

  kmp는 패턴의 앞 쪽부터 차례대로 비교를 시작하는 반면 (왼쪽에서 오른쪽)

  보이어모어는 패턴의 뒤 쪽부터 차례대로 비교를 시작한다. (오른쪽에서 왼쪽)

 

2.아이디어

- 브루트포스 방식과 어떤차이점을 가지고 수행시간을 단축시켜주느냐~ 인데.

- 보이어모어 알고리즘에서는 두가지의 큰 아이디어가 있다.

 

    -> Looking-glass heuristic

        : 패턴의 뒤 쪽부터 비교를 시작한다.

 

    ->Character-jump heuristic

        : 패턴을 구성할 수 있는 모든 글자의 마지막 발생위치를 미리 구해서 테이블 형태로 저장해 놓는다.

          텍스트와 패턴을 뒤쪽에서부터 비교해 오다가 불일치 발생시 그 때 위치의 텍스트 문자가 패턴의 마지막에 등장한 문자의 위치를

          맞춰 패턴을 옮긴다.

 

이해하기 위한 간단한 이론적 예시는 아래와 같다.

 

3. 전처리(preprocessing)

- 2번에서 말씀드렸다싶이 전처리 과정은 매우간단하며 패턴을 한번 쓱 스캔하면 되므로 시간도 오래걸리지 않습니다.

- 앞에서부터 보면서 뒤쪽에 등장할 때 마다 그 위치로 문자열테이블을 업데이트 해주시면 되겠습니다.

- 처음에 테이블을 만들어 -1로 초기화 시키고 위의 작업을 수행하면 전처리후에도 여전히 -1값을 가지는 문자는 텍스 

  트에는 있을 수 있으나 패턴에는 존재하지 않는 문자이므로 이 경우 패턴의 길이만큼 jump를 해주시면 되겠습니다.

 

4.The BoyerMoore Algorithm

-주의 해야할 점 하나는

  mismatch가 발생한 위치에 있는 문자가 현재 패턴의 문자열 위치보다 뒤쪽에 있을경우

  그대로 옮겼다가는 패턴이 다시 앞쪽으로 갈 수 있고 무한반복과 중복 처리 등이 발생할 수 있다.

  이 경우는 그냥 한칸 뒤로만 옮겨주는 것으로 대체한다.

5. 분석(Analysis)

- 시간 복잡도 : O(n*m+s)

- 최악의 경우를 분석해보면 심지어 브루트포스방식의 시간복잡도인 O(n*m)보다도 s만큼의 시간이 더 걸린다.

- 최악의 경우 예시를 보자면

        TEXT= aaaaaaaaaa........a

        PATTERN = baaa

-최악의 경우는 문자의 범위가 좁은 DNA Sequence나 이진문자열 같은 곳에서는 발생할 확룰이 꽤 있다.

- 하지만 영어 알파벳이나 한국어 처럼 문자의 범위가 매우 큰 경우 매우 효율적으로 빠르게 동작한다.

'알고리즘 > 문자열(string)' 카테고리의 다른 글

2. The KMP 알고리즘  (0) 2020.10.07
1. Brute-force 방식  (0) 2020.10.07

0. string

- character의 sequence 이다.

- string의 예시로서는

  -> HTML문서

  -> DNA sequence

  -> 등등....매우 많다.

- 아스키코드, binary alphabets, DNA alphabets( {A,C,G,T} )

- 보통 TEXT에서 PATTERN과 일치하는 SubString(그 위치)를 찾는 문제가 많다.

- 검색엔진, 텍스트 에디터, 생물학적 조사 등 을 할 때 주요하게 사용된다. 

 

1. 개요

- 가장 간단하고 naive한 방식의 알고리즘 이다.

- 텍스트의 위치 가능한 모든 자리에 PATTERN을 매치시켜 비교과정을 거친다.

- 비교과정 중 완벽하게 매치하거나 남은 텍스트의 길이보다 패턴의 길이가 더 길어질 경우 비교를 멈춘다.

 

2. 시간복잡도

- 워낙 간단해서 의사코드를 기재하진 않았지만 복잡도 분석을 해보면

- 텍스트의 길이 (m) 패턴의 길이 (n)  이라 하면 시간 복잡도는 O(n*m)

- m의 위치 가능한 모든 자리에서 n을 비교하기 때문에 최악의 경우 O(n*m) 이다.

- 최악의 경우 중 간단한 예시를 들어보면

 -> TEXT: AAAA........B

 -> PATTERN: AAAB

-이경우 불일치가 패턴의 맨 끝에 존재하므로 패턴을 매번 비교할 때 마다 끝문자가 나타날 때 까지 비교를 해야한다.

 

3. 장점 및 단점

- 장점은 알고리즘 자체가 매우 간단하다.

- 패턴이나 텍스트를 Preprocessing하는 과정이 없다.

- 알파벳의 범위가 좁을 경우 (위의 경우 처럼 a,b) 성능이 떨어진다.

- 영어나 한국어처럼 글자의 종류가 매우 많을경우는 나름 brute-force도 성능이 괜찮을 수 있다.

'알고리즘 > 문자열(string)' 카테고리의 다른 글

3.Boyer-Moore 알고리즘  (0) 2020.10.08
2. The KMP 알고리즘  (0) 2020.10.07

https://www.acmicpc.net/problem/1748

 

1748번: 수 이어 쓰기 1

첫째 줄에 N(1≤N≤100,000,000)이 주어진다.

www.acmicpc.net

문제 이해, 입출력  확인은 너무 쉽게 할 수 있고.....

 

자릿수를 확인해서 리턴해주는 함수를 하나 만든 뒤 자릿수의 합을 모두 더하였습니다.

 

'알고리즘 문제풀이 > 완탐' 카테고리의 다른 글

백준 17070 [C++]  (0) 2020.10.14
백준 17281 : 야구 [C++]  (0) 2020.10.13
완전탐색(경우의 수) , 순열, 재귀를 통한 구현, 모든 카드 경우의 수  (0) 2020.02.28
백준 14889  (0) 2020.02.24
백준 14888  (0) 2020.02.21

- 이번에 짜 본것은 임의의 개수의 카드 수 n 그리고 그 카드의 숫자를 입력 받았을 때

 

- 그 카드들을 가지고 만들 수 있는 모든경우의 수 를 출력하는 코드 입니다.

 

- 재귀를 사용하였고

 

- 알기 쉽게 표현 하자면 예를 들어 10 장의 카드의 모든 경우의 수를 구해야 할 때

 

- 한장을 선택을 한다면 !  나머지 9장만 선택을 하면됩니다 

 

- 이러한 방향으로 뽑아야 하는 카드의 수를 하나씩 줄이는 방식으로 구현하였고

 

- 코드 구현상에서는 임의의 카드를 하나 선택했다고 한다면 그 임의의카드와 벡터의 마지막 index 위치의 수 와 swap

 

- 을 한 이후 사이즈를 하나줄인 함수로 다시 들어갑니다 (즉 하나의 카드는 선택해서 뺴놓는 느낌)

 

<코드>

 

 

'알고리즘 문제풀이 > 완탐' 카테고리의 다른 글

백준 17281 : 야구 [C++]  (0) 2020.10.13
백준 1748 : 수 이어 쓰기 1  (0) 2020.03.24
백준 14889  (0) 2020.02.24
백준 14888  (0) 2020.02.21
백준 7568  (0) 2020.02.21

https://www.acmicpc.net/problem/14889

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

- dfs 를 이용한 완전 탐색 문제였습니다. (백트래킹 이라고도 하는...)

 

- 사실 저는 백트래킹이라는 개념을 딱히 그렇게 정의지어 배워본 적이 없어서 다른 문제하나를 풀다가

 

- 접한적은 있습니다만....

 

- 이문제는 dfs 느낌과 비슷하게 재귀를 이용 하여 모든 경우의 수를 모두 탐색 하는 방향으로 해결하였습니다.

 

- 다른건 어려운 것이 없고 최대20 명이 되는 n을 두팀에 나누어 넣는 모든 경우의 수를 어떻게 구현해 내는지가

 

- 핵심이였던 문제인 것 같습니다..

 

<코드>

'알고리즘 문제풀이 > 완탐' 카테고리의 다른 글

백준 1748 : 수 이어 쓰기 1  (0) 2020.03.24
완전탐색(경우의 수) , 순열, 재귀를 통한 구현, 모든 카드 경우의 수  (0) 2020.02.28
백준 14888  (0) 2020.02.21
백준 7568  (0) 2020.02.21
백준 6603  (0) 2020.02.01

+ Recent posts