반응형

문제링크: https://www.acmicpc.net/problem/1022

 

1022번: 소용돌이 예쁘게 출력하기

첫째 줄에 r1, c1, r2, c2가 주어진다. 모두 절댓값이 5000보다 작거나 같은 정수이고, r2-r1은 0보다 크거나 같고, 49보다 작거나 같으며, c2-c1은 0보다 크거나 같고, 4보다 작거나 같다.

www.acmicpc.net

 

구현문제였습니다.  회오리 모양으로 값이 증가하기에 구현하기 조금 까다로운 문제였습니다.

 

직관적으로 구현할때 흔히 할 수 있는 실수는 

 

1. 10001 * 10001 의 배열을 만들고 값들을 모두 저장한 후 결과를 도출하는 것입니다.

 

당연히 메모리 초과입니다.. 

 

2. 두번째 저지를 수 있는 실수는 재귀함수로 구현하는 것입니다.  5000번의 재귀가 호출하며 함수 호출과 매개변수 생성 등으로 시간초과를 가지게 됩니다. 

 

 

 

우선 정답 코드를 먼저 보여드리겠습니다. 

직관적이기 떄문에 쉽게 이해하실 수 있을거라고 생각합니다. 

#include <iostream>
#include <algorithm> // max 함수 사용
#include <cmath> // abs 함수 사용
using namespace std;

int r1, c1, r2, c2;
int map[50][5] = { 0 };
void solve() {
	int MAX = max(max(abs(r1), abs(c1)), max(abs(r2), abs(c2))); // max값을 찾는다.
	int val = 1; //소용돌이에서 값
	if (0 >= r1 && 0 >= c1 && 0 <= r2 && 0 <= c2)
		map[0 - r1][0 - c1] = val;

	int cnt = 0; // 현재의 카운트를 측정
	int y = 0, x = 0; // 좌표를 나타냄

	for (int i = 1; i <= MAX + 1; i++) {

		for (int i = 1; i <= 1 + cnt * 2; i++) {
			val++;
			x++;
			if (y >= r1 && x >= c1 && y <= r2 && x <= c2)
				map[y - r1][x - c1] = val;
		}
		for (int i = 1; i <= 1 + cnt * 2; i++) {
			val++;
			y--;
			if (y >= r1 && x >= c1 && y <= r2 && x <= c2)
				map[y - r1][x - c1] = val;
		}
		for (int i = 1; i <= 2 + cnt * 2; i++) {
			val++;
			x--;
			if (y >= r1 && x >= c1 && y <= r2 && x <= c2)
				map[y - r1][x - c1] = val;
		}
		for (int i = 1; i <= 2 + cnt * 2; i++) {
			val++;
			y++;
			if (y >= r1 && x >= c1 && y <= r2 && x <= c2)
				map[y - r1][x - c1] = val;
		}

		cnt++;
	}



}

int main() {
	cin >> r1 >> c1 >> r2 >> c2;
	solve();

	int h = abs(r2 - r1);
	int w = abs(c2 - c1);

	int MAX = 0;
	
	for (int i = 0; i <= h; i++) {
		for (int j = 0; j <= w; j++) {
			MAX = max(MAX, map[i][j]);
		}
	}
	
	//int MAX = max(max(map[0][0], map[0][w - 1]), max(map[h - 1][0], map[h - 1][w - 1])  ); // max값을 찾는다.
	int max_degree = 0;
	for (int i = 1; i <= MAX; i *= 10) {
		max_degree++;
	}
	for (int i = 0; i <= h; i++) {
		for (int j = 0; j <= w; j++) {
			int current_degree = 0;
			for (int k = 1; k <= map[i][j]; k *= 10)
				current_degree++;
			for (int k = current_degree; k < max_degree; k++)
				cout << ' ';

			cout << map[i][j] << ' ';
		}
		cout << '\n';
	}

}

solve함수에서 회오리로 이동하는 값들을 계산하면 반복문을 실행하고, 만약 (r1,c1)과 (r2,c2) 값 사이에 있다면 배열에 저장합니다.

 

그 이후에는 반복문을 통해 최대값의 자릿수를  max_degree에 저장하고 모든 값의 자릿수를 max_degree에 맞춰 적절히 공백을 넣어주면 됩니다. 

 

막상 짜고나면 간단해보이지만 코딩할 때는 어려운게 정석인 문제...

 

 

좀 더 효율적인 방법이 많을거 같아서 코드를 찾아봤습니다.

 

#include<cstdio>
int a[50][50], r1, c1, r2, c2, m, s;
int main() {
	scanf("%d%d%d%d", &r1, &c1, &r2, &c2);
	for (int i = r1; i <= r2; i++) {
		for (int j = c1; j <= c2; j++) {
			int x = i - r1, y = j - c1;
			if (i - j < 0) {
				if (i + j < 0) a[x][y] = 4 * i*i + i + 1 - j;
				else a[x][y] = 4 * j*j - 3 * j + 1 - i;
			}
			else {
				if (i + j < 0) a[x][y] = 4 * j*j - j + 1 + i;
				else a[x][y] = 4 * i*i + 3 * i + 1 + j;
			}
			if (a[x][y] > m) m = a[x][y];
		}
	}
	for (; m; m /= 10) s++;
	for (int i = 0; i <= r2 - r1; i++) {
		for (int j = 0; j <= c2 - c1; j++) printf("%*d ", s, a[i][j]);
		puts("");
	}
	return 0;
}

 

너무 간결하게 예쁜코드네요.

애초에 회오리가 규칙있게 값이 증가하기에 경우마다 값을 계산해서 O(200)만에 해결한 방법입니다. 

 

저렇게 짤 수 있으면 정말 잘하시는거겠지만 좋은 코드의 조건을 여러가지가 있을 수 있습니다.

어떤 사람에게는 직관적이고 이해하기 쉬운 코드일수도, 다른 사람에게는 짧고 시간이 짧게 드는 것일 수도 있습니다.

사람마다 기준이 다르기에 어떤게 옳다고 볼 수는 없습니다. 

 

꼭 직접 보지않고 구현해보세요. 구현문제의 핵심은 연습입니다.

 

화이팅 :) 

반응형

'알고리즘 > 구현' 카테고리의 다른 글

[백준] 1756-피자 굽기(C++)  (0) 2020.05.08
[백준] 1188-음식 평론가(C++)  (0) 2020.05.03
[백준] 5567-결혼식(C++)  (0) 2020.04.27
[백준] 2851-슈퍼 마리오(C++)  (0) 2020.04.26
[백준] 8979-올림픽(C++)  (0) 2020.04.26
반응형

문제링크:https://www.acmicpc.net/problem/5567

 

5567번: 결혼식

문제 상근이는 자신의 결혼식에 학교 동기 중 자신의 친구와 친구의 친구를 초대하기로 했다. 상근이의 동기는 모두 N명이고, 이 학생들의 학번은 모두 1부터 N까지이다. 상근이의 학번은 1이다. 상근이는 동기들의 친구 관계를 모두 조사한 리스트를 가지고 있다. 이 리스트를 바탕으로 결혼식에 초대할 사람의 수를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 상근이의 동기의 수 n (2 ≤ n ≤ 500)이 주어진다. 둘째 줄에는 리스트의 길이 m (1 ≤ m

www.acmicpc.net

 

구현문제입니다.

문제가 직관적이기 때문에 구현에 어려움은 없으실겁니다.

 

제가 고민했던 문제는 실행시간입니다.

m<= 10000 이기때문에  m을 입력받고 O(m*m)인 이중포문으로 구현하게 되면 O(100,000,000)으로 1억번 실행되기에 1초에 딱맞습니다. 그래서 시간초과가 날까 걱정했습니다.

 

#include <iostream>
using namespace std;
int n = 0, m = 0, result = 0;
bool visited[501] = { 0 };
int arr[10000][2] = { 0 };
int main() {
	cin >> n >> m;

	for (int i = 0; i < m; i++) 
		cin >> arr[i][0] >> arr[i][1];

	for (int i = 0; i < m; i++) {
		if (arr[i][0] == 1) { //상근이의 친구
			int val = arr[i][1];
			visited[val] = 1; //체크
			for (int j = 0; j < m; j++) {// 상근이 친구의 친구들도 체크
				if (arr[j][0] == val)
					visited[arr[j][1]] = 1;
				else if (arr[j][1] == val)
					visited[arr[j][0]] = 1;
			}
		}
	}

	for (int i = 1; i <= n; i++)
		if (visited[i] == 1) {
			result++;
			
		}
	cout << result - 1 << endl;
}

 

다행히 ac를 받았습니다.

 

 

시간도 얼마걸리지 않았습니다. ( 아마 테스트케이스에 극단값이 없을 수 있기 때문에 )

 

구현문제는 항상 좀더 컴팩트한 답을 생각하셔야 합니다.

 

 

#include <cstdio>
int main(){
    int n,m,a,b,ans=0;
    short int arr[501][501]={0,};
    scanf("%d%d",&n,&m);
    for(int i =0 ; i<m; i++)
        scanf("%d%d",&a,&b),arr[a][b] = 1,arr[b][a] = 1;
    for(int i=2; i<=n; i++){
        if(arr[1][i] ==1){
            ans++;
        }
        else{
            for(int j = 1; j<=n; j++){
                if(arr[i][j] == 1 && arr[j][1] == 1){
                    ans++;break;
                }}}}
    printf("%d\n",ans);
}

 

위 처럼 그래프에 값들을 저장하고 O(n*n)으로 계산할 수 있었습니다.

실행시간도 훨씬 적고 정작 배열의 크기도 작아 메모리도 더 적게 드는 답안이었습니다.

 

화이팅 :) 

반응형
반응형

문제링크: https://www.acmicpc.net/problem/2851

 

2851번: 슈퍼 마리오

문제 슈퍼 마리오 앞에 10개의 버섯이 일렬로 놓여져 있다. 이 버섯을 먹으면 점수를 받는다. 슈퍼 마리오는 버섯을 처음부터 나온 순서대로 집으려고 한다. 하지만, 모든 버섯을 집을 필요는 없고 중간에 중단할 수 있다. 중간에 버섯을 먹는 것을 중단했다면, 그 이후에 나온 버섯은 모두 먹을 수 없다. 따라서 첫 버섯을 먹지 않았다면, 그 이후 버섯도 모두 먹을 수 없다. 마리오는 받은 점수의 합을 최대한 100에 가깝게 만들려고 한다. 버섯의 점수가 주어

www.acmicpc.net

 

구현문제입니다. 단순히 반복되는 값들에서 100에 가까운 만큼 더해주면 되는 쉬운문제였습니다.

 

별다른 설명없이 정답코드입니다.

 

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

int arr[10] = { 0 };
int sum = 0; 
int main() {
	for (int i = 0; i < 10; i++) 
		cin >> arr[i];

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

		if (abs(100 - sum) >= abs(100 - (sum + arr[i])))
			sum += arr[i];
		else
			break;
	}
	cout << sum << endl;
}

 

 

위처럼 구현해주시면 됩니다. :) 

반응형
반응형

문제링크: https://www.acmicpc.net/problem/8979

 

8979번: 올림픽

입력의 첫 줄은 국가의 수 N(1 ≤ N ≤ 1,000)과 등수를 알고 싶은 국가 K(1 ≤ K ≤ N)가 빈칸을 사이에 두고 주어진다. 각 국가는 1부터 N 사이의 정수로 표현된다. 이후 N개의 각 줄에는 차례대로 각 국가를 나타내는 정수와 이 국가가 얻은 금, 은, 동메달의 수가 빈칸을 사이에 두고 주어진다. 전체 메달 수의 총합은 1,000,000 이하이다.

www.acmicpc.net

 

쉬운 구현문제입니다.

 

 

  1. 금메달 수가 더 많은 나라 
  2. 금메달 수가 같으면, 은메달 수가 더 많은 나라
  3. 금, 은메달 수가 모두 같으면, 동메달 수가 더 많은 나라 

위의 기준으로 배열을 정렬하고 같은 순위인 나라의 갯수를 세어준 후 빼주면 되는 쉬운 문제였습니다.

C++의 sort함수가 익숙하지 않으신분들은  아래 포스팅을 참고해주세요

https://gusdnr69.tistory.com/52?category=765773

 

sort함수 사용법

1. 헤더 선언 #include 2. sort( start, end) or sort( start, end, compare) ex) sort(arr, arr+n) sort(arr, arr+n,cmp) 시작주소와 끝주소 그리고 cmp함수가 필요합니다. sort( start, end) -> 이..

gusdnr69.tistory.com

 

정답코드입니다. 

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

struct country {
	int country_number;
	int gold;
	int sliver;
	int bronze;

};

bool cmp(country a, country b) {
	if (a.gold > b.gold) return true;
	else if (a.gold == b.gold) {
		if (a.sliver > b.sliver) return true;
		if (a.sliver == b.sliver) {
			if (a.bronze > b.bronze) return true;
		}
	}

	return false;
}

country arr[1001];
int n, k;
int n1, n2, n3, n4;
int result = 0,val=0;

int main() {
	cin >> n >> k;

	for (int i = 0; i < n; i++) {
		cin >> n1 >> n2 >> n3 >> n4;
		arr[i].country_number = n1;
		arr[i].gold = n2;
		arr[i].sliver = n3;
		arr[i].bronze = n4;
	}

	sort(arr, arr + n, cmp);

	for (int i = 0; i < n; i++) {
		if (arr[i].country_number == k) {
			result = i;
			break;
		}
	}
	for (int i = result - 1;; i--) {
		if (arr[i].gold != arr[result].gold || arr[i].sliver != arr[result].sliver || arr[i].bronze != arr[result].bronze) {
			break;
		}
		val++;
	}
	cout << result - val + 1 << endl;
}

구조체를 통해서 구현을 했습니다. 

천천히 보시고 꼭 직접 구현해보세요! 

화이팅 :)

반응형
반응형

문제링크:https://www.acmicpc.net/problem/1748

 

1748번: 수 이어 쓰기 1

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

www.acmicpc.net

 

전형적인 구현문제입니다. 

다만 n이 최대 1억번까지이기에 구현방법에 대해서 조금 생각해봐야했습니다.

 

저는 그냥 일반적인 논리로 접근했습니다.

#include <iostream>
using namespace std;
int n = 0, result = 0;

int main() {
	cin >> n;

	for (int i = 1; i <= n; i++) {
		if (i <= 9)
			result += 1;
		else if (i <= 99)
			result += 2;
		else if (i <= 999)
			result += 3;
		else if (i <= 9999)
			result += 4;
		else if (i <= 99999)
			result += 5;
		else if (i <= 999999)
			result += 6;
		else if (i <= 9999999)
			result += 7;
		else if (i <= 99999999)
			result += 8;
		else
			result += 9;
	}
	cout << result << endl;
}

 

네 당연히 ac입니다.

 

하지만 조금 더 효율적인 코드를 찾아봤습니다.

 

#include<cstdio>
int n, r;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i *= 10) 
		r += n - i + 1;
    printf("%d", r);
    return 0;
}

크으 ... 아름다운 코드...

 

위 코드의 핵심은 매번 반복문마다 1의자리수의 합을 더해주고, 다음 반복문에서는 2의 자리수의 합을 더해준다는 개념입니다. 

대략 120정도의 값을 대입해보시면 이해가 가실겁니다.

 

 

이렇게 구현문제는 풀어보는 것이 끝이 아니라 다른사람의 효율적인 코드를 보는게 더욱 도움이 된다고 생각합니다.

 

화이팅 :) 

 

반응형
반응형

문제출처:https://www.acmicpc.net/problem/14500

 

14500번: 테트로미노

폴리오미노란 크기가 1×1인 정사각형을 여러 개 이어서 붙인 도형이며, 다음과 같은 조건을 만족해야 한다. 정사각형은 서로 겹치면 안 된다. 도형은 모두 연결되어 있어야 한다. 정사각형의 변끼리 연결되어 있어야 한다. 즉, 꼭짓점과 꼭짓점만 맞닿아 있으면 안 된다. 정사각형 4개를 이어 붙인 폴리오미노는 테트로미노라고 하며, 다음과 같은 5가지가 있다. 아름이는 크기가 N×M인 종이 위에 테트로미노 하나를 놓으려고 한다. 종이는 1×1 크기의 칸으로 나누

www.acmicpc.net

 

시뮬레이션문제입니다.

차근차근 하나의 도형의 경우를 수를 적용해보셔야 합니다.

반복문 작성시 매번 테스트케이스를 입력해보면서 조기에 오류를 찾아야합니다...

다 작성하고 예외를 찾으려고 하면 절대 못찾아요....

 

주의하셔야 할 조건은 회전이나 대칭을 시켜도 된다 입니다.

 

1번 도형같은 경우에는  2가지 모양이 나옵니다.

 

 

한가지 좌우로 대칭하고 돌려도 한가지 모양만 나옵니다.

제일 괴랄한 모양으로 돌리고 대칭함으로써 총 8가지의 모양이 나옵니다.

 

대칭과 회전시 중복하는 모양이 생기기때문에 총 4가지 모양이 나옵니다.

역시 대칭과 회전시 중복하는 모양이 생기기때문에 총 4가지 모양이 나옵니다.

 

 

아래는 정답코드입니다.

코드확인해 보시고 꼭 직접 작성해서 풀어보세요 :) 

#include <iostream>
using namespace std;
/*
1번은 회전이 가능한 4가지 경우  -> 아래 오른쪽만 해주면 됨
3번 부터는 회전이나 대칭을 시키는게 가능하기에 각 8가지
*/
int n = 0, m = 0, result = 0;
int arr[501][501] = { 0 };

void num1() {
	for (int i = 0; i < n; i++)
		for (int j = 0; j <= m - 4; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i][j + 3]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i][j + 3]);

	for (int i = 0; i < m; i++)
		for (int j = 0; j <= n - 4; j++)
			if ((arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 3][i]) > result) result = (arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 3][i]);
}


void num2() {
	for (int i = 0; i < n - 1; i++)
		for (int j = 0; j < m - 1; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i + 1][j] + arr[i + 1][j + 1]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i + 1][j] + arr[i + 1][j + 1]);

}

void num3() {
	
	// 기본 모양
	for (int i = 0; i < m - 1; i++)
		for (int j = 0; j <= n - 3; j++)
			if ((arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 2][i + 1]) > result) result = (arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 2][i + 1]);
	// 기본 대칭
	for (int i = 1; i < m; i++)
		for (int j = 0; j <= n - 3; j++)
			if ((arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 2][i - 1]) > result) result = (arr[j][i] + arr[j + 1][i] + arr[j + 2][i] + arr[j + 2][i - 1]);
	//위로 90도
	for (int i = 1; i < n; i++)
		for (int j = 0; j <= m - 3; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i - 1][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i - 1][j + 2]);
	//위로 90도 대칭
	for (int i = 0; i < n - 1; i++)
		for (int j = 0; j <= m - 3; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i + 1][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i + 1][j + 2]);
	// 위로 180도
	for (int i = 2; i < n; i++)
		for (int j = 1; j < m; j++)
			if ((arr[i][j] + arr[i - 1][j] + arr[i - 2][j] + arr[i - 2][j - 1]) > result) result = (arr[i][j] + arr[i - 1][j] + arr[i - 2][j] + arr[i - 2][j - 1]);
	// 위로 180도 대칭 
	for (int i = 2; i < n; i++)
		for (int j = 0; j < m - 1; j++)
			if ((arr[i][j] + arr[i - 1][j] + arr[i - 2][j] + arr[i - 2][j + 1]) > result) result = (arr[i][j] + arr[i - 1][j] + arr[i - 2][j] + arr[i - 2][j + 1]);
	// 위로 270도 
	for (int i = 0; i < n - 1; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i + 1][j]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i + 1][j]);
	// 위로 270도  대칭 
	for (int i = 1; i < n; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i - 1][j]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i][j + 2] + arr[i - 1][j]);
}

void num4() {
	
	// 원래
	for (int i = 0; i < n - 2; i++)
		for (int j = 0; j < m - 1; j++)
			if ((arr[i][j] + arr[i + 1][j] + arr[i + 1][j + 1] + arr[i + 2][j + 1]) > result) result = (arr[i][j] + arr[i + 1][j] + arr[i + 1][j + 1] + arr[i + 2][j + 1]);
	//원래 대칭 
	for (int i = 0; i < n - 2; i++)
		for (int j = 1; j < m; j++)
			if ((arr[i][j] + arr[i + 1][j] + arr[i + 1][j - 1] + arr[i + 2][j - 1]) > result) result = (arr[i][j] + arr[i + 1][j] + arr[i + 1][j - 1] + arr[i + 2][j - 1]);
	//위로 90도
	for (int i = 1; i < n; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i - 1][j + 1] + arr[i - 1][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i - 1][j + 1] + arr[i - 1][j + 2]);
	//위로 90도 대칭
	for (int i = 0; i < n - 1; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i + 1][j + 1] + arr[i + 1][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i + 1][j + 1] + arr[i + 1][j + 2]);
			
}

void num5() {
	// ㅜ
	for (int i = 0; i < n - 1; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i + 1][j + 1] + arr[i][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i + 1][j + 1] + arr[i][j + 2]);
	// ㅗ
	for (int i = 1; i < n; i++)
		for (int j = 0; j < m - 2; j++)
			if ((arr[i][j] + arr[i][j + 1] + arr[i - 1][j + 1] + arr[i][j + 2]) > result) result = (arr[i][j] + arr[i][j + 1] + arr[i - 1][j + 1] + arr[i][j + 2]);
	// ㅏ
	for (int i = 0; i < n - 2; i++)
		for (int j = 0; j < m - 1; j++)
			if ((arr[i][j] + arr[i + 1][j] + arr[i + 2][j] + arr[i + 1][j + 1]) > result) result = (arr[i][j] + arr[i + 1][j] + arr[i + 2][j] + arr[i + 1][j + 1]);
	// ㅓ
	for (int i = 0; i < n - 2; i++)
		for (int j = 1; j < m; j++)
			if ((arr[i][j] + arr[i + 1][j] + arr[i + 2][j] + arr[i + 1][j - 1]) > result) result = (arr[i][j] + arr[i + 1][j] + arr[i + 2][j] + arr[i + 1][j - 1]);

}

int main() {
	cin >> n >> m;

	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			cin >> arr[i][j];
	num1();
	num2();
	num3();
	num4();
	num5();
	cout << result << "\n";

}
반응형

'알고리즘 > 시뮬레이션' 카테고리의 다른 글

[백준] 11559-Puyo Puyo(C++)  (0) 2020.05.03
[백준] 14891-톱니바퀴(C++)  (0) 2020.04.28
[백준] 1021-회전하는 큐(C++)  (0) 2020.04.02
[백준] 14499-주사위 굴리기  (0) 2020.01.29
[백준] 3190-뱀  (0) 2020.01.29
반응형

문제링크: https://www.acmicpc.net/problem/10844

 

10844번: 쉬운 계단 수

첫째 줄에 정답을 1,000,000,000으로 나눈 나머지를 출력한다.

www.acmicpc.net

 

전형적인 DP 문제였습니다.

1~9로 시작하는 값에 대한 테이블입니다.

 

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

즉, 1로 시작하는 네자리수는 5개 입니다. ( 1010, 1012, 1212, 1210, 1232, 1234)

 

이때    101~ 는  dp[2][1] 이구 12~ 는 dp[3][2] 입니다.

 

그외에 2~8로 시작하는 네자리수는 dp[i][j] = dp[i-1][j-1]+ dp[i-1][j+1]임을 확인할 수 있습니다. 

 

9로 시작할때는 98~이니 dp[i][j] = dp[i-1][j-1]

 

 즉 점화식은

arr[i][j] = arr[i - 1][j + 1] + arr[i - 2][j] (i=1일떄)

arr[i][j] = arr[i - 1][j + 1] + arr[i - 1][j - 1] (2~8)

arr[i][j] = arr[i - 1][j - 1] (i=9)

 

 

#include <iostream>
using namespace std;
int arr[101][10] = { 0 };
long long result = 0;
int n = 0;
int main() {
	cin >> n;	

	for (int i = 1; i <= 9; i++) // 초기값 설정
		arr[1][i] = 1;
	for (int j = 1; j <= 8; j++)
		arr[2][j] = 2;
	arr[2][9] = 1;

	for (int i = 3; i <= n; i++) {
		for (int j = 1; j <= 9; j++) {
			if (j == 1)
				arr[i][j] = (arr[i - 1][j + 1] + arr[i - 2][j]) % 1000000000;
			else if(j==9)
				arr[i][j] = (arr[i - 1][j - 1]) % 1000000000;
			else 
				arr[i][j] = (arr[i - 1][j + 1] + arr[i - 1][j - 1]) % 1000000000;
			
		}
	}

	for (int i = 1; i <= 9; i++) {
		result += arr[n][i];
	}
	result %= 1000000000;

	cout << result << endl;
}

arr 연산식마다 %1000000000 를 해주어야 오버플로우를 피할 수 있습니다. int 형의 범위를 넘어갈 수 있기 때문입니다.

반면 result는 long long 형으로 정의했기 때문에 1~9까지의 값을 다 더하고 나눠도 지장이 없습니다.

 

위 테이블을 보고 직접 점화식을 유추해보세요! 화이팅!

 

반응형
반응형

문제링크:https://www.acmicpc.net/problem/2206

 

2206번: 벽 부수고 이동하기

N×M의 행렬로 표현되는 맵이 있다. 맵에서 0은 이동할 수 있는 곳을 나타내고, 1은 이동할 수 없는 벽이 있는 곳을 나타낸다. 당신은 (1, 1)에서 (N, M)의 위치까지 이동하려 하는데, 이때 최단 경로로 이동하려 한다. 최단경로는 맵에서 가장 적은 개수의 칸을 지나는 경로를 말하는데, 이때 시작하는 칸과 끝나는 칸도 포함해서 센다. 만약에 이동하는 도중에 한 개의 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면, 벽을 한 개 까지 부수고 이동

www.acmicpc.net

 

bfs문제입니다.

근데 기존의 bfs와 다른점은 벽을 한번 부수고 갈 수 있다는 점입니다. 

 

처음으로 생각하셔야 할 것은 각 점마다 벽을 뚫고 이동하는 최단경로와 벽을 뚫지 않고 이동하는 최단경로를 고려해주어야 한다는 점입니다. (1)

 

두번째로 생각하셔야 할 것은 최단거리검색이라는 점입니다. 그렇기 때문에 방문한 곳이라면 굳이 다시 방문할 필요가 없다는 것을 인지하셔야 합니다. (이 점은 기존 bfs와 같습니다.) (2)

 

1. 벽이 아니고 현재 방문한적이 없을 때 ( 벽을 뚫고 방문한 것과 벽을 뚫지 않고 도착한 것 두가지를 모두 고려해주어야 합니다. 왜냐하면 이미 벽을 뚫고 도착해서 최단경로값을 표시하는 경우가 있기 때문입니다.)

     1) 큐에 좌표와 벽부수기가능여부를 넣어줍니다.

     2) 최단거리값에 1더해주기 

 

2. 벽이고 뚫을 수 있을 때 (벽을 뚫은 적이 있다면 더이상 벽을 뚫을 수 없고, 뚫은 적이 없을 경우 해당 벽을 뚫고 벽을 뚫은 최단경로에 포함시켜줍니다. )

     1) 큐에 좌표와 불가능을 넣어줍니다.

     2) 벽을 뚫은 최단거리에 기존 벽뚫기 전 최단거리값에 1을 더해 넣어줍니다. 

 

테스트 케이스

8 8
01000100
01010100
01010100
01010100
01010100
01010100
01010100
00010100

 

5 8
01000000
01010000
01010000
01010011
00010010

 

 

정답코드입니다.

#include <iostream>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
int n = 0, m = 0;
bool arr[1001][1001] = { 0 }; // 0 1을 저장하는 배열 
int  visited[1001][1001][2] = { 0 }; // 방문거리 
string v; // 문자열로 받고 arr에 다시 넣기위해 쓰는 변수 
queue<int> que[3]; //y,x,벽가능여부 

int x_ar[4] = { 1,0,-1, 0};
int y_ar[4] = { 0,1,0,-1 };

void bfs() {
	visited[1][1][1] = 1;
		
	que[0].push(1); //y
	que[1].push(1); //x
	que[2].push(1); // 벽뚫기 가능

	while (que[0].empty() != true) { // 큐가 빌때 까지 반복합니다. 
		int yy = que[0].front();
		int xx = que[1].front();
		int talent = que[2].front(); //1이면  벽뚫기 가능
		que[0].pop();
		que[1].pop();
		que[2].pop(); 

		for (int i = 0; i < 4; i++) {
			int y = yy + y_ar[i];
			int x = xx + x_ar[i];
			if (y >= 1 && y <= n && x >= 1 && x <= m) { // 배열범위에 포함되는지 확인 
				if (arr[y][x] == 0 && visited[y][x][talent] == 0) {//벽이 아니고 방문한 적 없을때
					que[0].push(y); //y
					que[1].push(x); //x
					que[2].push(talent); // 벽뚫기 가능
					visited[y][x][talent] = visited[yy][xx][talent] + 1;
				}
				else if (arr[y][x] == 1 && talent == 1) { //벽이고 아직 안 뚫었을때 
					visited[y][x][talent - 1] =  visited[yy][xx][talent] + 1;
					que[0].push(y); //y
					que[1].push(x); //x
					que[2].push(0); //벽을 더이상 뚫지 못한다. 
				}
			}

		}


	}

}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> v;
		for (int j = 1; j <= m; j++)
			if (v[j-1] == '1')
				arr[i][j] = 1;
	}


	bfs(); 
	
	
	if (visited[n][m][1] == 0 && visited[n][m][0] == 0)
		cout << -1 << '\n';
	else if(visited[n][m][1] != 0 && visited[n][m][0] != 0)
		cout << min(visited[n][m][0], visited[n][m][1]) << '\n';
	else
		if(visited[n][m][1] == 0)
			cout << visited[n][m][0] << '\n';
		else
			cout << visited[n][m][1] << '\n';
}

 

반응형

'알고리즘 > BFS' 카테고리의 다른 글

[백준] 4179-불!(C++)  (0) 2020.05.06
[백준] 5427-불(C++)  (0) 2020.05.06
[백준] 8061-Bitmap  (0) 2020.03.26
[백준] 1389-케빈 베이컨의 6단계 법칙(C++)  (0) 2020.03.22
[백준] 9205-맥주 마시면서 걸어가기(C++)  (0) 2020.03.12

+ Recent posts