-Summary-
CodeUp 11문제(1081번, 1082번, 1091번 ~ 1099번) c언어 풀이 Write Up
-1081-
주사위 2개의 면의 개수가 입력되는데, 그 입력을 바탕으로 나올 수 있는 모든 수의 조합을 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS // 취약한 scanf 함수를 오류 없이 사용하기 위해 작성
#include <stdio.h>
int main() // 메인 함수
{
int m, n; // 입력 값을 담을 변수 선언
scanf("%d %d", &m, &n); // 입력
for (int i = 1; i <= m; i++) // 2중 for문을 통해 모든 조합 출력
{
for (int j = 1; j <= n; j++)
{
printf("%d %d\n", i, j);
}
}
return 0;
}
모든 조합을 출력해야하므로 for문에서 1씩 증가하며 사용되는 변수 i, j를 통해 조합을 출력하는 식으로 접근했다.
입력 값을 각각 m, n 변수에 넣고, 주사위가 2개이므로 for문을 2개 작성하고 초기 값을 i = 1, j = 1, 조건은 i <= m, j <= n으로 정했다. 초기 값을 0이 아닌 1로 정한 이유는, 주사위의 면이 1부터 입력한 값까지 존재하기 때문이고, 조건이 <=인 이유는 출력 결과를 보면 입력한 값까지 조합에 사용되기 때문에, i, j가 입력 값까지 도달하도록 한 것이다.
i와 j가 각각 1부터 입력 값까지 1씩 증가하며 변한다는 점을 이용해 2번째 for문 안에 이 i와 j를 출력하는 printf문을 작성하면 문제를 해결할 수 있다.
디버깅 표로 작성해보면
입력 : 2 3
i | j | 출력 값
1 | 1 | 1 1
1 | 2 | 1 2
1 | 3 | 1 3
2 | 1 | 2 1
2 | 2 | 2 2
2 | 3 | 2 3
이렇게 1081번 문제의 출력 예시와 동일한 것을 알 수 있다.
-1082-
입력된 16진수로 구구단을 작성하는 것이 목적이다. 이 때 구구단은 1~9까지만 곱하는게 아닌 0x1~0xF까지 곱해줘야한다. 또한 출력 결과를 알파벳은 대문자로 출력하고 줄을 바꿔가며 출력해야한다. 은근 머리를 썻던 문제다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a; // 입력 받을 수
scanf("%X", &a); // 입력
for (int i = 1; i < 16; i++) // 0x1 ~ 0xF까지
{
printf("%X*%X=%X\n", a, i, a*i); // %X 이렇게 16진수를 대문자 형태로 출력
}
return 0;
}
16진수를 대문자로 출력해야하므로 조건문이나 아스키 코드값을 이용해서 소문자를 대문자로 바꿔줄까 생각하다가 %x가 아닌 %X 서식 지정자를 사용하면 16진수를 대문자로 출력할 수 있다는 것이 생각나 %X를 사용하는 방법으로 접근했다.
먼저 구구단을 수행할 수를 입력 받을 변수를 선언하고 scanf로 입력을 받는다. 그 후 for문을 돌리는데, 곱하는 수는 1부터 시작하므로 초기 식의 초기 값은 1로 설정한다. 그리고 조건식은 i < 16으로 하는데, 그 이유는 언뜻보기에는 16개의 숫자를 곱해줘야할 것 같지만 사실상 1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 이렇게 15개의 숫자를 곱해줘야한다. 따라서 16번 반복이 아닌 15번 반복으로 해야하는 것이다.
반복문 안에서는 printf와 서식 지정자 %X를 이용해서 출력하는데, %X는 16진수를 대문자로 출력해주기 때문에 사용했다. 형식은 %X*%X=%X\n이고, 각각에 들어갈 수는 입력 받은 구구단을 수행할 수, for문으로 1씩 증가하는 i 그리고 입력 받은 구구단을 수행할 수와 i를 곱해준 수를 각각의 서식 지정자에 해당하는 부분에 넣어주면 된다.
-1091-
시작 값, 곱할 값, 더할 값, 몇 번째 인지를 나타내는 수가 공백을 기준으로 입력된다. 입력 된 값을 바탕으로 매 번째마다 시작 값부터 곱할 값을 곱하고 더할 값을 더해주는데, 지정된 번째까지 이 과정을 반복해 해당 값을 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS // 취약한 scanf 함수를 오류 없이 사용하기 위해 작성
#include <stdio.h>
int main() // 메인 함수
{
long long int a, m, d, n; // 오버플로우를 방지하기 위해 long long형으로 입력 받을 변수 선언
scanf("%lld %lld %lld %lld", &a, &m, &d, &n); // 입력
for (int i = 1; i < n; i++) // 입력 된 번째 수 만큼 반복하면서 곱셈, 덧셈을 수행
{
a *= m;
a += d;
}
printf("%lld", a); // 결과 값 출력
return 0;
}
시작 값부터 곱셈과 덧셈을 지정 번째까지 반복해서 수행해야하므로 for 반복문을 사용해서 매 반복마다 곱셈, 덧셈을 해주도록 구상했고, 또한 누적된 값을 담는 변수를 새로 선언하기 보다는 초기 값을 담을 변수인 a에 곱셈과 덧셈을 수행하도록 했다.
먼저 입력 값을 담은 변수인 a, m, d, n을 선언했는데, 자료형은 int가 아닌 long long int형으로 선언했다. 각각의 입력 값의 범위를 봤을 때는 오버플로우를 미처 예상하지 못했는데
결과를 보니 int형 자료형으로는 부족해 오버플로우가 일어난다는 것을 깨닫고 long long int형으로 선언했다.
그 후 for문을 통해 번째마다 곱셈과 덧셈이 수행되도록 작성했는데, 이 때 초기 값을 1, 조건을 i < n(번째 값)으로 작성함으로써 입력한 번째보다 1 적게 반복하도록 했다. 그 이유는 이 초기 값이 1번째에 해당하기 때문이다. 만약 초기 값을 0으로 한다면 곱셈, 덧셈을 1번씩 수행한 값이 1번째 값이 되기 때문에 올바른 결과보다 곱셈, 덧셈을 한 번 더한 값이 출력되게 된다.
조건은 이렇게 작성하고 for문 내의 코드는 a *=m, a += d으로 작성하여 매 반복마다 곱셈, 덧셈 값으로 입력된 값을 시작 값에 곱하고 더해주도록 한다.
이 for문의 반복이 끝났을 때는 시작 값을 입력 받은 변수인 a에는 입력 된 번째에 해당되는 결과 값이 담겨 있을 것이므로, 이 값을 출력하면 된다.
-1092-
같은 날 동시에 가입한 3명의 방문 주기가 입력된다. 이 입력된 값들을 바탕으로 이 3명이 동시에 방문하는 날을 출력하는 것이 목적이다. 이 날은 1/1 같은 날짜가 아닌 동시에 가입한 날을 기준으로 며칠 후에 동시에 방문하는지를 구하는 것이다.
#define _CRT_SECURE_NO_WARNINGS // 취약한 scanf 함수를 오류 없이 사용하기 위해 작성
#include <stdio.h>
int main() // 메인 함수
{
int a, b, c; // 입력 받을 변수 선언
scanf("%d %d %d", &a, &b, &c); // 입력
for (int i = 1;; i++) // i를 1씩 증가하면서 반복하면서 i가 세 수의 공배수일 때 값을 출력하고 멈춤
{
if (i % a == 0 && i % b == 0 && i % c == 0)
{
printf("%d", i);
break;
}
}
return 0;
}
방문 주기가 다른 3명이 동시에 방문하는 날은 세 수의 최소 공배수를 구하는 것과 다름 없다. 따라서 무한 루프를 돌리며 특정 변수의 값을 1씩 증가 시키는데, 매 반복마다 해당 값이 최소 공배수인지 체크를 하는식으로 접근했다.
a와 b의 최소 공배수는 a와 b로 나눴을 때 나머지가 0이라는 점을 이용하는데, 먼저 3명의 방문 주기를 변수 a, b, c로 입력 받고 초기식, 변화식만 작성하고 조건식은 비워둔 for문을 작성했다. 그 이유는 for문에 조건식을 적는 까닭이 몇 번 반복할지를 정해주는 건데, 이 3명이 언제 동시에 방문할지는 입력 값에 달려 있으므로 몇 번 반복할지를 알 수 없기 때문이다. 따라서 조건식을 비움으로써 무한으로 반복되도록 했다.
이 for문 안에는 간단한 if문을 작성했다. 조건은 i를 a, b, c로 각각 나누고 나머지가 0인지 확인하는 것인데, 이 때 나머지가 모두 0이어야 최소 공배수이므로 &&(and) 연산자로 각 조건을 이어줬다.
이 조건에 만족한다면 해당 i의 값이 최소 공배수(동시에 방문하는 날)이므로 이 값을 출력하고 break로 반복문을 끝내줬다.
-1093-
첫 줄에 출석 번호를 부른 횟수가 입력되고, 두 번째 줄에 부른 번호가 횟수만큼 입력되는데, 이 입력된 값들을 바탕으로 1번부터 번호가 불린 횟수를 공백으로 구분하여 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int number[23]; // 각 번호의 부른 횟수가 저장될 배열
int count, callNumber = 0; // count : 입력 받을 횟수 callNumber : 부른 번호
for (int i = 0; i < 23; i++) // 배열 number의 각 요소들을 0으로 초기화
{
number[i] = 0;
}
for (scanf("%d", &count); count > 0; count--) // 입력 된 횟수만큼 반복해서 번호를 입력 받음.
{
scanf("%d", &callNumber);
number[callNumber - 1] += 1; // 해당 번호의 부른 횟수에 해당되는 number 배열의 요소 값에 + 1
}
for (int i = 0; i < 23; i++) // number 배열의 요소들을 공백으로 구분하여 출력
{
printf("%d ", number[i]);
}
return 0;
}
각 번호가 입력 받은 횟수를 기록하는 배열을 만들어 특정 번호가 입력될 때마다 해당 번호의 요소의 값 +1을 하는 식으로 접근했다.
먼저 각 번호의 횟수가 저장될 배열 number를 선언(번호가 23까지 있다하니 크기는 23으로 정했다.)하고 for문으로 해당 배열의 크기 만큼 반복을 하며 각 요소에 0을 넣어줬다. 그 후 입력 된 횟수만큼 반복을 하도록 for문을 선언했는데, 코드를 간결화 시키기 위해 scanf를 for문 초기식에 넣었다. 이 횟수를 count 변수에 저장하는데, 매 반복마다 이 count 변수의 값을 -1 해줌으로써 count가 0보다 크지 않을 때 반복을 끝내도록 했다. 즉 횟수만큼 반복하게 되는 것이다.
for 안의 코드는 먼저 scanf 함수로 부른 번호를 입력 받고 number의 입력된 번호 -1번째 요소에 +1을 해준다.
입력된 번호 -1 번째 번호의 횟수를 +1 해주는 이유는, 배열은 인덱스가 0부터 존재하기 때문에 크기가 23이어도 0 ~ 22의 인덱스를 갖게 된다. 즉 number 배열의 0 인덱스의 요소는 1번의 횟수를 의미하기 때문이 입력된 번호 -1 인덱스의 횟수를 증가시켜준 것이다.
횟수만큼 입력을 받고 number 배열의 입력된 번호 -1 인덱스 요소에 +1을 해준 후 다시 for문으로 number 배열에 저장된 요소(횟수)들을 공백으로 구분해 출력하도록 했다.
-1094-
1093번 문제와 똑같이 첫 줄에는 번호를 부른 횟수가 입력되고, 두 번째 줄에 부른 번호들이 입력된다. 1093번 문제가 각 번호들이 얼마나 호출됐는지를 출력하는 것이었다면 1094번 문제의 목적은 부른 번호들을 역순으로 출력하는 것이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int number[10000]; // 부른 번호가 저장될 배열
int count = 0; // 번호를 부른 횟수가 저장될 변수
scanf("%d", &count); // 횟수 입력
for (int i = 0; i < count; i++) // 횟수만큼 반복하며 number 배열에 부른 번호를 저장
{
scanf("%d", &number[i]);
}
for (; count > 0; count--) // 역순으로 배열 내 요소들을 출력
{
printf("%d ", number[count - 1]);
}
return 0;
}
부른 번호들을 배열에 담고, 그 배열을 역순으로 출력하는 식으로 생각했다.
먼저 부른 번호들이 저장될 배열을 선언한다. 이 배열의 크기는 10000으로 설정하는데 그 이유는 횟수의 개수가 1 ~ 10000 사이기 때문에 나올 수 있는 가장 많은 횟수인 10000을 기준으로 정해준 것이다. 그 다음에 횟수를 담을 변수를 선언하고 scanf로 해당 변수에 횟수 입력 값을 넣는다.
입력된 횟수만큼 for문을 돌려주면서 입력된 부른 번호들을 순차적으로 number 배열에 넣어준 후, 이 배열의 요소들을 역순으로 출력하면 된다. 나는 매 반복마다 횟수를 담은 변수를 1 감소시켜 주면서 이 변수가 0이 됐을 때 반복을 끝내도록 for 반복식을 작성했다.
출력은 number 배열의 횟수 - 1 인덱스의 값을 출력시켜주는데, 그 이유는 count가 10일 때 인덱스가 0부터 시작하는 배열의 특성상 인덱스 0~9까지 값이 저장되기 때문이다. 따라서 -1을 해줌으로써 10일 때는 9, 9일 때는 8 이런식으로 배열의 인덱스를 고려해서 작성한 것이다.
-1095-
1093, 1094번 문제들과 똑같이 첫 번째 줄에는 횟수, 두 번째 줄에는 부른 번호들이 입력된다. 이번에는 입력된 번호들 중 가장 빠른 번호를 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int count = 0; // 횟수 입력 값을 담을 변수
int min; // 작은 값을 판별할 때 사용할 변수
int tmp; // 입력된 부른 번호를 담을 임시 변수
scanf("%d", &count); // 횟수 입력
scanf("%d", &min); // 첫 번째 부른 번호 입력
for (int i = 1; i < count; i++) // count - 1 만큼 반복하며 입력 값이 min보다 작은지 판별 후, 작다면 min에 해당 값을 할당
{
scanf("%d", &tmp);
if (tmp < min)
min = tmp;
}
printf("%d", min); // 반복문을 돌며 만들어진 가장 작은 값을 출력
return 0;
}
이번 문제는 1093, 1094번 문제와 다르게 배열이 필요 없을 것 같아서 배열을 선언하지 않았다. 매 반복마다 입력된 값이 그 시점까지의 가장 작은 값이 담긴 변수와 비교해서 작다면 변수에 입력된 값을 넣어주고 아니라면 아무 동작 없이 새로운 값을 받는 식으로 생각했다.
먼저 횟수를 담을 변수 count, 가장 작은 값이 담길 변수 min, 입력된 번호를 임시로 담을 변수 tmp를 각각 선언했다. 그리고 scanf로 횟수와 첫 번째 부른 번호를 각각 count와 min에 넣어준다. min에 첫 번째 변수를 넣어주는 이유는 for문안에서 이 입력된 값과 min 변수를 비교해서 입력 값이 min보다 작다면 이 min에 해당 입력 값을 넣어주는 식으로 가장 작은(빠른) 번호를 구할 것이기 때문에 이 min에 들어갈 초기 값이 필요하다. 첫 번째 입력 시점에서는 첫 번째 입력 값이 가장 작기(비교 대상이 없으므로) 때문에 첫 번째 값을 바로 min으로 입력 받는 것이다.
그 후 for문으로 count - 1만큼 반복을 하는데, count - 1만큼 반복하는 이유는 이미 앞에서 첫 번째 값을 입력 받아서 for문 안에서는 두 번째 값부터 입력 받기 때문이다. 따라서 반복하는 횟수는 1 줄여줘야한다.
for문 내에서는 tmp에 부른 번호를 하나씩 입력을 받고 이 입력 값이 min의 값보다 작은지 체크한다. 만약 min보다 작다면 이 값이 현재 시점에서 가장 작은 값이 되므로 min에 해당 값을 넣어준다. 이 과정을 count - 1만큼 반복한 후 min에 들어있는 값이 바로 가장 빠른(작은) 번호다.
for 반복이 끝난 후 min 변수의 값을 출력해주면 된다.
-1096-
첫 줄에 입력 받을 횟수가 입력되고, 두 번째 줄부터 흰 돌의 위치를 x, y 값으로 입력 받는다. 19 * 19 바둑판에서 입력 받은 흰 돌의 위치를 바탕으로 흰 돌이 있는 위치는 1, 없는 위치는 0으로 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int board[19][19]; // 바둑판 배열 선언
int count = 0, x = 0, y = 0;
// count : 입력 받을 횟수를 담을 변수 x : 입력된 좌표의 x 값 y : 입력된 좌표의 y 값
for (int i = 0; i < 19; i++) // 바둑판 배열의 요소들 초기화
{
for (int j = 0; j < 19; j++)
{
board[i][j] = 0;
}
}
scanf("%d", &count); // 횟수 입력
for (int i = 0; i < count; i++)
{// 횟수만큼 반복하며 흰돌의 좌표 입력, 입력된 좌표를 바탕으로 바둑판 배열의 요소 변경
scanf("%d %d", &x, &y);
board[x - 1][y - 1] = 1;
}
for (int i = 0; i < 19; i++) // 바둑판 배열의 요소들 출력
{
for (int j = 0; j < 19; j++)
{
printf("%d ", board[i][j]);
}
printf("\n");
}
return 0;
}
바둑판 배열을 만들고 모든 요소를 0으로 만든 후 입력 받은 좌표만 1로 바꿔주는 식으로 접근했다.
먼저 바둑판의 상황이 기록될 배열 board를 [19][19] 크기로 선언했다. 그리고 입력 받을 횟수, 입력 좌표 x, y를 담을 변수를 선언했고 이중 for문을 돌려 board안의 요소들을 모두 0으로 초기화했다.
그 후 횟수를 입력 받고 횟수만큼 반복하는 for문을 생성하는데, 이 for문에서 흰 돌의 좌표 x, y를 입력 받고 board[x-1][y-1]에 요소를 흰 돌을 뜻하는 1로 바꿔준다. board[x][y]가 아닌 board[x-1][y-1]로 작성한 이유는 사람 기준에서는 맨 처음 좌표가 1, 1로 시작되지만 배열로 작성한 바둑판에서는 첫 좌표가 0, 0으로 시작하기 때문에 1의 오차가 생긴다. 따라서 입력된 좌표 -1을 해줌으로써 올바른 배열 요소의 값을 1로 바꿔주는 것이다.
위 for문이 끝난다면 사용자가 입력한 좌표에 흰 돌을 모두 넣어준 것이므로 이중 for문을 돌려 바둑판 배열의 요소들을 모두 출력한다. 이때 출력 결과를 보면 19 글자씩 19 줄에 출력하므로 두 번째 for문으로 19개의 요소들을 출력한 후 printf("\n")을 써줘서 한 줄씩 개행해줘야 한다.
-1097-
먼저 바둑알이 깔려 있는 상황이 19*19 크기로 입력된다. 그리고 횟수가 입력되는데, 이 횟수만큼 십자 뒤집기 좌표가 입력된다. 입력된 좌표를 기준으로 십자뒤집기를 수행한 결과를 출력하는 것이 목적이다.
십자 뒤집기가 뭔지 몰라서 조금 해맸었는데, 십자 뒤집기는 입력된 좌표를 기준으로 +(십자) 모양에 해당되는 위치들이 0이라면 1로 1이라면 0으로 바꿔주는 것이다.
0 0 0
0 1 0
0 0 0
예를 들어 위 바둑판에서 2, 2에 십자 뒤집기를 수행한다면
0 1 0
1 0 1
0 1 0
이렇게 입력 좌표의 십자에 해당되는 요소들이 마치 not 연산을 한 것처럼 변하는 것이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int board[19][19]; // 바둑판 배열 선언
int count = 0, x = 0, y = 0;
// count : 입력 받을 횟수를 담을 변수 x : 입력된 좌표의 x 값 y : 입력된 좌표의 y 값
for (int i = 0; i < 19; i++) // 바둑판 배열의 요소들 입력
{
for (int j = 0; j < 19; j++)
{
scanf("%d", &board[i][j]);
}
}
scanf("%d", &count); // 횟수 입력
for (int i = 0; i < count; i++) // 횟수만큼 반복
{
scanf("%d %d", &x, &y); // 십자 뒤집기 좌표 입력
for (int j = 0; j < 19; j++)
{// 해당 좌표를 기준으로 십자에 해당하는 인덱스들의 요소 값을 not 연산
board[x - 1][j] = !board[x - 1][j];
board[j][y - 1] = !board[j][y - 1];
}
}
for (int i = 0; i < 19; i++) // 바둑판 출력
{
for (int j = 0; j < 19; j++)
{
printf("%d ", board[i][j]);
}
printf("\n");
}
return 0;
}
십자 뒤집기 좌표로 입력된 x, y 값을 for문으로 19번(가로, 세로의 길이) 반복시키면서 [x][1~19] [1~19][y] 이런식으로 십자에 해당되는 모든 요소들을 not 연산시키는 방법으로 접근했다.
먼저 1096번과 똑같이 바둑판 배열 선언, 입력 받을 횟수, 십자 뒤집기 좌표의 x, y를 담을 변수를 선언하고 바둑판의 크기만큼 2중으로 for문을 돌리면서 해당 좌표의 값을 입력 받았다.
그 후 횟수를 입력 받고 for문으로 횟수만큼 반복하는데, for문 내에서 십자 뒤집기 좌표를 입력 받고 19번 for문으로 반복을 시켜줌으로써 [입력 받은 x-1][0~18], [0~18][입력 받은 y-1] 이렇게 해당 좌표에서 십자에 해당되는 영역의 요소를 모조리 not 연산을 해줬다. x-1, y-1을 해준 이유는 배열은 0부터 시작하기 때문에 1 기준으로 입력된 좌표와 오차가 생기기 때문이다.
횟수만큼 해당 좌표를 기준으로 십자 뒤집기를 해준 후 마지막으로 2중 for문으로 바둑판의 요소들을 모두 출력시키면 된다. 주의할 점은 1096번과 마찬가지로 19개씩 19줄로 출력하므로 두 번째 for문에서 19개를 출력한 다음에는 꼭 개행을 해줘야한다.
-1098-
첫 줄에 격자판의 가로, 세로 크기가 입력되고 두 번째 줄에 막대의 개수, 세 번째 줄에는 개수만큼 막대의 길이, 방향, 좌표가 입력된다. 이 막대들을 모두 놓은 상태의 격자판을 출력하는 것이 목적이다. 막대가 있는 곳은 1, 없는 곳은 0으로 출력하면 된다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int board[100][100]; // 격자판 배열
int xCount, yCount, count, len, direct, x, y;
// xCount : 격자판 가로 yCount : 격자판 세로 count : 막대의 개수 len : 막대의 길이
// direct : 막대의 방향 x, y : 막대의 위치 좌표
scanf("%d %d", &xCount, &yCount); // 격자판 가로, 세로 길이 입력
for (int i = 0; i < xCount; i++) // 입력된 가로, 세로 길이를 기준으로 격자판의 요소들 초기화
{
for (int j = 0; j < yCount; j++)
{
board[i][j] = 0;
}
}
scanf("%d", &count); // 막대의 개수 입력
for (int i = 0; i < count; i++) // 개수만큼 반복
{
scanf("%d %d %d %d", &len, &direct, &x, &y); // 해당 막대의 길이, 방향, 좌표 입력
for (int j = 0; j < len; j++) // 길이만큼 반복
{
if (!direct) // 방향이 가로라면
{
board[x - 1][y - 1 + j] = 1; // 해당 위치의 요소 1로 변경
}
else // 방향이 세로라면
{
board[x - 1 + j][y - 1] = 1; // 해당 위치의 요소 1로 변경
}
}
}
for (int i = 0; i < xCount; i++) //xCount, yCount를 기준으로 격자판 출력
{
for (int j = 0; j < yCount; j++)
{
printf("%d ", board[i][j]);
}
printf("\n");
}
}
격자판을 입력 받은 세로와 가로의 길이를 바탕으로 2중 for문으로 생성한 후, 개수만큼 for문을 돌리는데 이 때 해당 막대의 길이만큼 중첩 for문을 돌리면서 해당 길이, 방향에 맞게 막대가(1이) 생성되게끔 구상했다. 한 가지 주의할점이 있는데, 이 문제에서는 x좌표가 가로를 의미하지 않고 세로를 의미한다. 또한 지금까지는 아무 생각없이 2차원 배열에서 첫 번째 []가 가로를 의미한다 생각했지만 사실은 첫 번째는 세로를 의미한다.
[b] ->
[a] 0 0 0
↓ 0 0 0
0 0 0
예시가 좀 엉망이지만 [a][b]가 있을 때 [a]는 세로, [b]는 가로를 의미하는 것이다. 바둑판 문제 때는 정사각형이라서 크게 상관이 없었지만 이 문제는 직사각형 격자판도 존재하므로 가로, 세로 구분이 중요하다.
먼저 입력 받은 격자판의 높이와 가로 길이를 기준으로 격자판을 이중 for문을 돌려 생성했다. for문의 조건식은 각각 i, j가 세로, 가로보다 작을 때까지 반복하며 해당 요소에 0을 넣어 초기화시켜줬고, 그 후 막대의 개수를 입력받았다.
격자판 초기화 후 입력 받은 횟수만큼 반복을 하며 scanf로 막대의 길이, 방향, x, y 좌표를 입력 받은 후, 이 입력받은 길이만큼 반복을 돌리는 중첩 for문을 만들어 막대를 생성해줬다. 이 중첩 for문에서는 if문으로 direct(방향)이 0이 아닌지 검사하고 0이 아니라면 가로(1)을 뜻하므로 [x-1][y-1+j] 인덱스의 요소를 1로 만들어줬다.
먼저 -1을 해주는 이유는 앞서 말했듯이 배열 기준 좌표(인덱스)와 입력된 좌표가 1 차이가 있기 때문이고, y-1에 j를 더해주는 이유는 좌표를 기준으로 오른쪽으로 막대의 길이만큼 1로 만들어줘야하기 때문이다. 마찬가지로 direct가 0이면 세로를 의미하므로 [x-1+j][y-1] = 1을 작성해줬다.
위 과정을 거쳐 격자판에 막대를 뒀으면 2중 for문으로 격자판의 요소를 세로, 가로의 길이를 기준으로 출력해주면 된다. 참고로 가로 길이만큼 2번째 for문에서 출력한 후 \n 개행문자로 한 칸 개행해주는 것을 잊으면 안된다.
미로 상자를 입력 받는데, 이 미로 상자에서 2는 먹이 1은 벽, 0은 갈 수 있는 곳이다. 개미는 무조건 2,2(배열 기준 1,1)에서 위치하는데, 이 개미는 오른쪽에 벽이 없으면 무조건 오른쪽으로 가고, 오른쪽이 막혀있다면 아래로 움직인다. 이렇게 미로 상자 내에서 개미가 움직이는데, 먹이(2)를 만나거나 더 이상 움직일 수 없는 경우(오른쪽, 아래 모두 벽(1)일 때)까지 이동 경로를 9로 표시해서 출력하는 것이 목적이다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int board[10][10]; // 10*10 크기의 미로 상자 배열 선언
int antPosX = 1, antPosY = 1; // 개미의 현재 좌표를 담을 변수
for (int i = 0; i < 10; i++) // 미로 상자 배열의 요소 입력
{
for (int j = 0; j < 10; j++)
{
scanf("%d", &board[i][j]);
}
}
if (board[antPosX][antPosY] == 2) // 개미의 위치에 먹이가 존재한다면..
{
board[antPosX][antPosY] = 9; // 해당 위치를 이동한 경로를 뜻하는 9로 바꾼 후 출력으로 이동
goto PRINT;
}
board[antPosX][antPosY] = 9; // 현재 좌표의 배열 인덱스를 이동한 경로를 뜻하는 9를 넣어줌
while (1) // 먹이에 도착하거나 더 이상 갈 수 없을 때까지
{
if (board[antPosX][antPosY + 1] == 1) // 오른쪽에 벽이 있다면
{
if (board[antPosX + 1][antPosY] == 1) // 아래에 벽이 있다면
break; // 더 이상 이동할 수 없으므로 반복을 끝냄
antPosX++; // 아래에는 벽이 없으므로 아래로 이동
}
else // 오른쪽에 벽이 없을 경우
antPosY++; // 오른쪽으로 이동
if (board[antPosX][antPosY] == 2) // 이동한 위치에 먹이가 있다면
{
board[antPosX][antPosY] = 9; // 해당 좌표의 배열 인덱스를 이동한 경로를 뜻하는 9를 넣어줌
break; // 먹이를 찾았으므로 반복 멈춤
}
board[antPosX][antPosY] = 9; // 먹이가 없다면 해당 좌표의 배열 인덱스를 이동한 경로를 뜻하는 9를 넣어줌
}
PRINT:
for (int i = 0; i < 10; i++) // 이동한 경로가 나타내진 미로 상자의 요소들을 출력
{
for (int j = 0; j < 10; j++)
{
printf("%d ", board[i][j]);
}
printf("\n");
}
}
이 문제도 마찬가지로 x는 세로, y는 가로라는 점, 그리고 입력한 좌표와 배열에서의 좌표는 1 차이난다는 점을 명심해야한다.
먼저 10*10 크기의 미로 상자 배열을 선언, 그리고 현재 개미의 x, y 좌표를 담을 변수들을 선언하고 초기 위치인 1,1을 넣어줬다. 그리고 2중 for문을 각각 10번씩 반복하도록 설정해 scanf로 미로 상자의 요소들을 배열에 입력 받았다. 먹이가 개미의 초기 위치에 존재할 수도 있으므로 if문을 써줘 개미의 위치가 먹이라면 해당 위치의 배열 요소를 이동한 경로를 뜻하는 9로 바꾼 후 미로 상자 출력문 바로 위에 있는 레이블 PRINT 위치로 goto를 사용해 이동한다.
일단 시작 위치에 먹이가 없다면 이동해야하므로 시작 위치를 일단 9로 바꿔주고 while(1) 이렇게 무한 루프를 돌린다. 루프 안에서 개미의 오른쪽에 벽이 있는지 확인하는데([x][y+1]) 벽이 없다면 오른쪽으로 이동(y+1)하고 만약 벽이 있다면 아래에도 벽이 있는지 확인한다. 아래에도 벽이 있다면 더 이상 갈 수가 없으므로 break로 루프를 끝낸다. 아래에 벽이 없다면 아래로 이동(x+1)한다.
사실상 이동을 하는게 아닌 그냥 개미의 좌표만 더해주는 것인데, 만약 개미의 좌표를 변동시킨 후 미로 상자 배열에서 해당 위치에 먹이(2)가 존재한다면 해당 위치의 요소를 9로 바꿔준 후 반복을 끝낸다.(먹이를 찾았으므로) 만약 먹이가 없다면 현재 위치의 요소를 9로 바꿔준 후, 위 과정을 먹이를 찾거나 혹은 더 이상 이동할 수 없을 때까지 반복한다.
개미 이동을 수행하는 반복을 마친 후 이동한 경로가 나타내진 미로 상자 배열을 출력하면 된다.
'Old (2021.01 ~ 2021.12) > Algorithm' 카테고리의 다른 글
CodeUp 1098 : 설탕과자 뽑기 (0) | 2021.03.07 |
---|---|
CodeUp 1810 : (포인터) 부분 문자열 (0) | 2021.03.07 |
CodeUp 1581 : swap 함수 만들기 (0) | 2021.03.07 |
CodeUp 1076 ~ 1099 With Python (0) | 2021.02.04 |
CodeUp 1001 ~ 1075 With Python (0) | 2021.02.01 |