백준 ( 쉽게, 깔끔하게, 시간복잡도가 좋게 )
카테고리: Algorithm
Chapter 01 그리디
01-1 회의실 배정 ( 1931 )
- 한 개의 회의실이 있는데 이를 사용하고자 하는 N개의 회의에 대하여 회의실 사용표를 만들려고 한다
- 각 회의 I에 대해 시작시간과 끝나는 시간이 주어져 있고, 각 회의가 겹치지 않게 하면서 회의실을 사용할 수 있는 회의의 최대 개수를 찾아보자
- 단, 회의는 한번 시작하면 중간에 중단될 수 없으며 한 회의가 끝나는 것과 동시에 다음 회의가 시작될 수 있다
- 회의의 시작시간과 끝나는 시간이 같을 수도 있다
- 이 경우에는 시작하자마자 끝나는 것으로 생각하면 된다
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int totalmeeting = 0;
int meeting = 0;
cin>>meeting;
// 미팅 목록을 기록한다 ( 끝나는 시간 기준 정렬을 하기 위해, 끝나는 시간이 앞에 오게 저장한다 )
vector<pair<int,int>> vMeeting;
for(int i = 0; i < meeting; ++i)
{
int start = 0, end = 0;
cin>>start>>end;
vMeeting.push_back(make_pair(end,start));
}
sort(vMeeting.begin(), vMeeting.end());
// 마지막 미팅 시간 이후 미팅 목록 중에서 가장 빠른 시간대를 예약한다
int lastTime = 0;
for(int i = 0; i < meeting; ++i)
{
if(lastTime <= vMeeting[i].second)
{
lastTime = vMeeting[i].first;
totalmeeting = totalmeeting + 1;
}
}
cout<<totalmeeting;
return 0;
}
01-2 수 묶기 ( 1744 )
- 수열이 주어졌을 때, 수열의 각 수를 적절히 묶었을 때, 그 합이 최대가 되게 하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int total, onecount, zerocount;
vector<int> positive;
vector<int> negative;
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
// 숫자들을 분류한다
cin >> total;
for (int i = 0; i < total; i++)
{
int value = 0;
cin >> value;
if (value > 1) positive.push_back(value);
else if (value < 0) negative.push_back(value);
else if (value == 0) zerocount++;
else onecount++;
}
// 자리수를 맞춰준다
if (positive.size() % 2 == 1)
positive.push_back(1);
if (negative.size() % 2 == 1)
{
if (zerocount == 0) negative.push_back(1);
else negative.push_back(0);
}
// 양수는 오름차순 음수는 내림차순으로 정렬한다
sort(positive.begin(), positive.end());
sort(negative.rbegin(), negative.rend());
// 두개씩 계산한다
int sum = onecount;
for (int i = 0; i < positive.size(); i += 2)
sum += positive[i] * positive[i + 1];
for (int i = 0; i < negative.size(); i += 2)
sum += negative[i] * negative[i + 1];
cout << sum;
}
01-3 A와 B ( 12904 )
- 주어진 조건을 이용해서 S를 T로 만들 수 있는지 없는지 알아내는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int main()
{
string S = "", T = "";
cin>>S;
cin>>T;
while(true)
{
if(T.size() == S.size())
{
if(S == T)
{
cout << 1 << endl;
break;
}
else
{
cout << 0 << endl;
break;
}
}
// 문자열 T를 문자열 S로 역변환해 문제를 해결한다
if(T[T.size()-1] == 'A')
{
T.pop_back();
continue;
}
else if(T[T.size()-1] == 'B')
{
T.pop_back();
reverse(T.begin(), T.end());
continue;
}
cout << 0 << endl;
break;
}
}
Chapter 02 완전탐색
02-1 테트리스 ( 3019 )
- 블록을 놓는 서로 다른 방법의 수를 구하는 프로그램을 작성하시오
// https://hsdevelopment.tistory.com/506 참고
#include <bits/stdc++.h>
using namespace std;
const int MAX = 105;
int board[MAX], c, p;
vector<string> v;
int simulation(int number)
{
int ret = 0;
if (number == 1)
{
v.push_back("0");
v.push_back("0000");
}
else if (number == 2)
{
v.push_back("00");
}
else if (number == 3)
{
v.push_back("001");
v.push_back("10");
}
else if (number == 4)
{
v.push_back("100");
v.push_back("01");
}
else if (number == 5)
{
v.push_back("000");
v.push_back("01");
v.push_back("101");
v.push_back("10");
}
else if (number == 6)
{
v.push_back("000");
v.push_back("00");
v.push_back("011");
v.push_back("20");
}
else if (number == 7)
{
v.push_back("000");
v.push_back("02");
v.push_back("110");
v.push_back("00");
}
for (int i = 0; i < v.size(); i++)
{
int len = v[i].length();
vector<int> temp;
for (auto k : v[i])
{
temp.push_back(k - '0');
}
for (int j = 0; j + len <= c; j++)
{
bool calc = true;
for (int k = j + 1; k < j + len; k++)
{
// board의 모든 구역에 temp를 맞춰봐야 하니까 board수식과 temp 수식이 다르다
if (board[k] - board[k - 1] != temp[k - j] - temp[k - j - 1])
{
calc = false;
break;
}
}
if (calc)
{
++ret;
}
}
}
return ret;
}
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> c >> p;
for (int i = 0; i < c; i++)
{
cin >> board[i];
}
cout << simulation(p) << endl;
return 0;
}
02-2 치킨 배달 ( 15686 )
- 도시의 치킨 거리가 가장 작게 될지 구하는 프로그램을 작성하시오
02-3 동전 게임 ( 9079 )
- 상우는 이것을 최소 횟수의 연산으로 실행하고 싶어한다
02-4 꽃길 ( 14620 )
- 돈이 많지 않은 진아를 위하여 진아가 꽃을 심기 위해 필요한 최소비용을 구해주자
02-5 도영이가 만든 맛있는 음식 ( 2961 )
- 신맛과 쓴맛의 차이가 가장 작은 요리를 만드는 프로그램을 작성하시오
02-6 오목 ( 2615 )
- 아직 승부가 결정되지 않았는지를 판단하는 프로그램을 작성하시오
02-7 링크와 스타트 ( 15661 )
- 첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다
02-8 A와 B 2 ( 12919 )
- 주어진 조건을 이용해서 S를 T로 만들 수 있는지 없는지 알아내는 프로그램을 작성하시오
02-9 부분 삼각 수열 ( 1548 )
- 삼각 수열의 최대 길이를 구하는 프로그램을 작성하시오
02-10 제곱수 찾기 ( 1025 )
- 연두가 만들 수 있는 정수 중에서 가장 큰 완전 제곱수를 구해보자 완전 제곱수란 어떤 정수를 제곱한 수이다
Chapter 03 DFS와 백트래킹
03-1 테크노미노 ( 14500 )
- 테트로미노는 반드시 한 정사각형이 정확히 하나의 칸을 포함하도록 놓아야 하며, 회전이나 대칭을 시켜도 된다
// https://9967han.tistory.com/15 참고
#include<bits/stdc++.h>
using namespace std;
const int MAX = 501;
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
int N, M, ans = 0;
void getMaxNum(vector<vector<int>>& mymap, vector<vector<bool>>& visited, int x, int y, int cnt, int curScore)
{
// 블록이 4개라면 스코어 갱신이 가능한지 체크
if(cnt == 4)
{
if(ans < curScore) ans = curScore;
return;
}
// 현재 노드에서 만들수 있는 모든 도형을 만들자
for(int i = 0; i < 4; ++i)
{
int nx = x + dx[i];
int ny = y + dy[i];
if(nx < 0 || ny < 0 || ny >= N || nx >= M || visited[ny][nx]) continue;
visited[ny][nx] = true;
getMaxNum(mymap, visited, nx, ny, cnt + 1, curScore + mymap[ny][nx]);
visited[ny][nx] = false;
}
}
int main()
{
vector<vector<int>> mymap(MAX, vector<int>(MAX, 0));
vector<vector<bool>> visited(MAX, vector<bool>(MAX, false));
cin >> N >> M;
for(int y = 0; y < N; ++y)
{
for(int x = 0; x < M; ++x)
{
cin >> mymap[y][x];
}
}
for(int y = 0; y < N; ++y)
{
for(int x = 0; x < M; ++x)
{
// 모든 노드를 방문한다
visited[y][x] = true;
getMaxNum(mymap, visited, x, y, 1, mymap[y][x]);
visited[y][x] = false;
// ㅏ ㅓ ㅗ ㅜ 를 만들자
if(y-1 >= 0 && x+1 < M && y+1 < N) //ㅏ ( ㅏ 같은 경우는 x-1 >= 0 이라는 조건이 있으면 안된다는 것을 명심하자 )
{
ans = max(ans, (mymap[y-1][x] + mymap[y][x] + mymap[y][x+1] + mymap[y+1][x]));
}
if(x-1 >= 0 && y-1 >= 0 && y+1 < N) //ㅓ
{
ans = max(ans, (mymap[y-1][x] + mymap[y][x] + mymap[y][x-1] + mymap[y+1][x]));
}
if(x-1 >= 0 && y-1 >= 0 && x+1 < M) //ㅗ
{
ans = max(ans, (mymap[y-1][x] + mymap[y][x] + mymap[y][x-1] + mymap[y][x+1]));
}
if(x-1 >= 0 && x+1 < M && y+1 < N) //ㅜ
{
ans = max(ans, (mymap[y][x] + mymap[y][x-1] + mymap[y][x+1] + mymap[y+1][x]));
}
}
}
cout << ans;
}
03-2 무기 공학 ( 18430 )
- 길동이가 만들 수 있는 부메랑들의 강도 합의 최댓값을 출력하는 프로그램을 작성하시오
// 백트래킹
03-3 파이프 옮기기 1 ( 17070 )
- 파이프의 한쪽 끝을 (N, N)로 이동시키는 방법의 개수를 구해보자
#include<bits/stdc++.h>
using namespace std;
void dfs(vector<vector<int>>& visited, int y, int x, int dir, int housecount)
{
visited[y][x] = visited[y][x] + 1;
// 경로 1
if(dir == 0 || dir == 2)
{
if(x < housecount && visited[y][x+1] != -1)
{
dfs(visited, y, x+1, 0, housecount);
}
}
// 경로 2
if(dir == 1 || dir == 2)
{
if(y < housecount && visited[y+1][x] != -1)
{
dfs(visited, y+1, x, 1, housecount);
}
}
// 경로 3
if(x < housecount && y < housecount && visited[y][x+1] != -1 && visited[y+1][x] != -1 && visited[y+1][x+1] != -1)
{
dfs(visited, y+1, x+1, 2, housecount);
}
return;
}
int main()
{
int housecount = 0;
cin >> housecount;
// https://leeeegun.tistory.com/m/3 참고
vector<vector<int>> visited(housecount+1, vector<int>(housecount+1, false));
for(int i = 1; i <= housecount; i++)
for(int j = 1; j <= housecount; j++)
{
int value = 0;
cin >> value;
if(value == 0)
{
visited[i][j] = 0;
}
else
{
visited[i][j] = -1;
}
}
dfs(visited, 1, 2, 0, housecount);
if(visited[housecount][housecount] != -1) cout << visited[housecount][housecount] << endl;
else cout << 0 << endl;
}
03-4 넴모넴모 (Easy) ( 14712 )
- 네모가 게임을 그만두었을 때 나올 수 있는 “넴모”의 배치의 가짓수를 구하여라
// 백트래킹
03-5 일곱 난쟁이 ( 2309 )
- 왕비를 피해 일곱 난쟁이들과 함께 평화롭게 생활하고 있던 백설공주에게 위기가 찾아왔다
- 일과를 마치고 돌아온 난쟁이가 일곱 명이 아닌 아홉 명이었던 것이다
- 아홉 명의 난쟁이는 모두 자신이 “백설 공주와 일곱 난쟁이”의 주인공이라고 주장했다
- 뛰어난 수학적 직관력을 가지고 있던 백설공주는, 다행스럽게도 일곱 난쟁이의 키의 합이 100이 됨을 기억해 냈다
- 아홉 난쟁이의 키가 주어졌을 때, 백설공주를 도와 일곱 난쟁이를 찾는 프로그램을 작성하시오
#include <bits/stdc++.h>
using namespace std;
vector<int> vecValue;
void dfs(vector<bool>& visited, int targetcount, int targetsum, int level, int cnt, int sum)
{
// targetcount에 도달하면 난쟁이 키의 합이 targetsum인지 확인하자
if(cnt == targetcount)
{
if(sum == targetsum)
{
for(int i = 0; i < vecValue.size(); ++i)
{
if(visited[i] == true)
cout << vecValue[i] << endl;
}
exit(0);
}
}
// 레벨의 끝에 도달했다면 리턴하자
if(level == vecValue.size())
return;
else
{
// 레벨의 끝이 아니고 현재 인덱스를 더하는 경우
visited[level] = true;
dfs(visited, targetcount, targetsum, level + 1, cnt + 1, sum + vecValue[level]);
// 레벨의 끝이 아니고 현재 인덱스를 더하지 않는 경우
visited[level] = false;
dfs(visited, targetcount, targetsum, level+1, cnt, sum);
}
}
int main(void)
{
ios_base::sync_with_stdio(false);
cout.tie(NULL);
cin.tie(NULL);
for(int i = 0; i < 9;i++)
{
int value;
cin >> value;
vecValue.push_back(value);
}
sort(vecValue.begin(), vecValue.end());
vector<bool> visited(vecValue.size());
dfs(visited, 7, 100, 0, 0, 0);
return 0;
}
03-6 1, 2, 3 더하기 ( 9095 )
- 정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오
#include <bits/stdc++.h>
using namespace std;
int answer = 0;
void dfs(int target, int sum)
{
// 타겟이 맞는지 체크
if(target <= sum)
{
if(target == sum)
{
answer++;
}
return;
}
// 경로 1
dfs(target, sum + 1);
// 경로 2
dfs(target, sum + 2);
// 경로 3
dfs(target, sum + 3);
}
int main()
{
ios_base::sync_with_stdio(false);
cout.tie(NULL);
cin.tie(NULL);
int TestCase = 0;
vector<int> vTestCase;
cin>>TestCase;
for(int i = 0; i < TestCase; ++i)
{
int value = 0;
cin>>value;
vTestCase.push_back(value);
}
for(int i = 0; i < vTestCase.size(); ++i)
{
dfs(vTestCase[i], 0);
cout<<answer<<endl;
answer = 0;
}
return 0;
}
03-7 에너지 모으기 ( 16198 )
- N과 에너지 구슬의 무게가 주어졌을 때, 모을 수 있는 에너지 양의 최댓값을 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int max_energe = 0;
void dfs(vector<int> vBall, int erasenumber, int sum_energe)
{
if(vBall.size() == 2)
{
return;
}
// MAX 에너지 갱신
int current_energe = sum_energe + (vBall[erasenumber - 1] * vBall[erasenumber + 1]);
vBall.erase(vBall.begin()+erasenumber);
if(max_energe <= current_energe)
max_energe = current_energe;
// 두번째 이후 에너지 구슬 선택
for(size_t erasenumber = 1; erasenumber < vBall.size() - 1; ++erasenumber)
{
dfs(vBall, erasenumber, current_energe);
}
}
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int ball = 0;
cin >> ball;
vector<int> vBall;
for(int i = 0; i < ball; ++i)
{
int value = 0;
cin >> value;
vBall.push_back(value);
}
// 첫번째 에너지 구슬 선택
for(size_t erasenumber = 1; erasenumber < ball - 1; ++erasenumber)
{
dfs(vBall, erasenumber, 0);
}
cout << max_energe << endl;
return 0;
}
03-8 암호 만들기 ( 1759 )
- 가능성 있는 암호들을 모두 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
void dfs(vector<char> vChar, int L, int C, int length, int level, string curstr)
{
// 문자열 길이 체크
if (length == L)
{
int mo = 0, ja = 0;
for (int i = 0; i < L; ++i)
{
if (curstr[i] == 'a' || curstr[i] == 'e' || curstr[i] == 'i' || curstr[i] == 'o' || curstr[i] == 'u')
mo++;
else
ja++;
}
if (1 <= mo && 2 <= ja)
cout << curstr << endl;
return;
}
// 레벨의 끝에 도달했다면 리턴하자
if (level == C)
{
return;
}
else
{
// 문자열을 추가해주는 경우
dfs(vChar, L, C, length + 1, level + 1, curstr + vChar[level]);
// 문자열을 추가해주지 않는 경우
dfs(vChar, L, C, length, level + 1, curstr);
}
}
int main()
{
int L = 0, C = 0;
cin >> L >> C;
vector<char> vChar;
for (int i = 0; i < C; ++i)
{
char value;
cin >> value;
vChar.push_back(value);
}
sort(vChar.begin(), vChar.end());
dfs(vChar, L, C, 0, 0, "");
return 0;
}
03-9 N과 M (1) (15649)
- 자연수 N과 M이 주어졌을 때, 아래 조건을 만족하는 길이가 M인 수열을 모두 구하는 프로그램을 작성하시오
// 백트래킹 유형
#include<bits/stdc++.h>
using namespace std;
#define MAX 9
int N, M;
int arr[MAX];
bool visited[MAX];
void dfs(int count)
{
if(count == M)
{
for(auto i = 0; i < M; ++i)
cout << arr[i] << " ";
cout << '\n';
}
else
{
for(auto i = 1; i <= N; ++i)
{
if(!visited[i])
{
visited[i] = true;
arr[count] = i;
dfs(count + 1);
visited[i] = false;
}
}
}
}
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> N >> M;
dfs(0);
}
03-10 쿼드트리 ( 1992 )
- 이 영상을 압축한 결과를 출력하는 프로그램을 작성하시오
Chapter 04 BFS
04-1 뱀과 사다리 게임 ( 16928 )
- 게임은 정육면체 주사위를 사용하며, 주사위의 각 면에는 1부터 6까지 수가 하나씩 적혀있다. 게임은 크기가 10×10이고, 총 100개의 칸으로 나누어져 있는 보드판에서 진행된다
- 보드판에는 1부터 100까지 수가 하나씩 순서대로 적혀져 있다
- 플레이어는 주사위를 굴려 나온 수만큼 이동해야 한다
- 예를 들어, 플레이어가 i번 칸에 있고, 주사위를 굴려 나온 수가 4라면, i+4번 칸으로 이동해야 한다
- 만약 주사위를 굴린 결과가 100번 칸을 넘어간다면 이동할 수 없다
- 도착한 칸이 사다리면, 사다리를 타고 위로 올라간다
- 뱀이 있는 칸에 도착하면, 뱀을 따라서 내려가게 된다
- 즉, 사다리를 이용해 이동한 칸의 번호는 원래 있던 칸의 번호보다 크고, 뱀을 이용해 이동한 칸의 번호는 원래 있던 칸의 번호보다 작아진다
- 게임의 목표는 1번 칸에서 시작해서 100번 칸에 도착하는 것이다
- 게임판의 상태가 주어졌을 때, 100번 칸에 도착하기 위해 주사위를 굴려야 하는 횟수의 최솟값을 구해보자
#include<bits/stdc++.h>
using namespace std;
const int MAX = 102;
void game(vector<int>& warp, vector<bool>& visited, int location, int c)
{
queue<pair<int, int>> que;
que.push(make_pair(location, c));
visited[location] = true;
while (!que.empty())
{
// 다음 위치 세팅
int x = que.front().first;
int cnt = que.front().second;
que.pop();
for (int i = 1; i <= 6; i++)
{
// 주사위 숫자만큼 이동
int nx = x + i;
int ncnt = cnt + 1;
// 도착 했다면 정답을 출력
if (nx == 100)
{
cout << ncnt << endl;
return;
}
// 이 조건문이 없어도 정상 실행되는것 확인
else if (nx < 100)
{
// 워프를 태울수 있을때 까지 태운다
while (warp[nx] != 0)
{
nx = warp[nx];
}
// 아직 방문한적 없는 노드라면 큐에 넣는다
if (!visited[nx])
{
que.push(make_pair(nx, ncnt));
visited[nx] = true;
}
}
}
}
}
int main()
{
ios_base::sync_with_stdio(false); cout.tie(NULL); cin.tie(NULL);
vector<int> warp(MAX, 0);
vector<bool> visited(MAX, false);
int sadari, snake;
cin >> sadari >> snake;
for (int i = 0; i < sadari; i++)
{
int from = 0, to = 0;
cin >> from >> to;
warp[from] = to;
}
for (int i = 0; i < snake; i++)
{
int from = 0, to = 0;
cin >> from >> to;
warp[from] = to;
}
game(warp, visited, 1, 0);
return 0;
}
04-2 연구소 ( 14502 )
- 연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int answer = 0;
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
// 여기서는 참조자를 사용해도 된다
void BFS(vector<vector<int>>& mymap)
{
queue<pair<int, int>> que;
// 바이러스 최초 위치들을 모두 큐에 담는다
for (int y = 0; y < mymap.size(); y++)
{
for (int x = 0; x < mymap[0].size(); x++)
{
if (mymap[y][x] == 2)
que.push({ x, y });
}
}
// 바이러스를 최대한 퍼뜨린다
while (!que.empty())
{
int x = que.front().first;
int y = que.front().second;
que.pop();
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || mymap[0].size() <= nx || mymap.size() <= ny || mymap[ny][nx] != 0)
continue;
que.push({ nx, ny });
mymap[ny][nx] = 2;
}
}
// 바이러스가 모두 퍼진 상태에서 안전 영역 크기를 계산한다
int cnt = 0;
for (int y = 0; y < mymap.size(); y++)
{
for (int x = 0; x < mymap[0].size(); x++)
{
if (mymap[y][x] == 0)
cnt++;
}
}
answer = max(answer, cnt);
}
// 여기서는 참조자를 사용하면 안된다
void DFS(vector<vector<int>> mymap, int x, int y, int cnt)
{
mymap[y][x] = 1;
cnt = cnt - 1;
// 벽을 더이상 세울수 없다면 바이러스를 퍼뜨린다
if (cnt == 0)
{
BFS(mymap);
return;
}
// 벽 2개를 세울수 있는 모든 경우의 수를 체크한다
for (int y = 0; y < mymap.size(); y++)
{
for (int x = 0; x < mymap[0].size(); x++)
{
if (mymap[y][x] == 0)
DFS(mymap, x, y, cnt);
}
}
}
int main()
{
int N, M;
cin >> N >> M;
vector<vector<int>> mymap(N, vector<int>(M, 0));
for (int y = 0; y < N; y++)
{
for (int x = 0; x < M; x++)
cin >> mymap[y][x];
}
// 벽 3개를 세울수 있는 모든 경우의 수를 체크한다
for (int y = 0; y < N; y++)
{
for (int x = 0; x < M; x++)
{
if (mymap[y][x] == 0)
DFS(mymap, x, y, 3);
}
}
cout << answer << endl;
return 0;
}
04-3 점프 게임 ( 15558 )
- 각 칸의 정보가 주어졌을 때, 게임을 클리어 할 수 있는지, 없는지 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
int x, y, x_limit;
}node;
int main()
{
vector<vector<bool>> visited(2, vector<bool>(200001, false));
int N, K;
cin >> N >> K;
for (int y = 0; y < 2; y++)
{
for (int x = 0; x < N; x++)
{
char value;
cin >> value;
if (value == '0')
{
visited[y][x] = true;
}
else
{
visited[y][x] = false;
}
}
}
// 필요한 변수 초기화
bool flag = false;
queue<node> que;
que.push({ 0, 0, 0 });
visited[0][0] = true;
while (!que.empty())
{
// 다음 위치 세팅
node cur = que.front();
int x = cur.x, y = cur.y, x_limit = cur.x_limit;
que.pop();
// 목적지를 넘어서면 플래그를 true로 세팅한다
if (N <= x)
{
flag = true;
break;
}
//전진
if (visited[y][x + 1] == false)
{
visited[y][x + 1] = true;
que.push({ x + 1, y, x_limit + 1 });
}
//후진
if (visited[y][x - 1] == false && x_limit < x - 1)
{
visited[y][x - 1] = true;
que.push({ x - 1, y, x_limit + 1 });
}
//점프
if (visited[1 - y][x + K] == false)
{
visited[1 - y][x + K] = true;
que.push({ x + K, 1 - y, x_limit + 1 });
}
}
// 플래그에 따라 결과 출력
if (flag == false)
cout << 0;
else
cout << 1;
}
04-4 4연산 ( 14395 )
- 정수 s가 주어진다
- 정수 s의 값을 t로 바꾸는 최소 연산 횟수를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
const long long MAX = 1e9;
set<long long> visited;
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int start, target;
cin >> start >> target;
if(start == target)
{
cout << 0 << "\n";
return 0;
}
// 필요한 변수 초기화
queue<pair<long long, string>> que;
que.push({start, ""});
while (!que.empty())
{
// 다음 숫자 세팅
long long n = que.front().first;
string temp = que.front().second;
que.pop();
// 원하는 숫자라면 연산자 출력후 리턴
if (n == target)
{
cout << temp << "\n";
return 0;
}
// 현재 노드에서 방문할 수 있는 노드를 모두 큐에 담는다 ( https://twpower.github.io/92-how-to-use-set-in-cpp // count 함수에 대한 정보 )
if (0 <= n * n && n * n <= MAX && visited.count(n*n) == 0 )
{
que.push({ n * n, temp + "*" });
visited.insert(n*n);
}
if (0 <= n + n && n + n <= MAX && visited.count(n+n) == 0)
{
que.push({ n + n, temp + "+" });
visited.insert(n + n);
}
if (0 <= n - n && n - n <= MAX && visited.count(n-n) == 0)
{
que.push({ n - n, temp + "-" });
visited.insert(n - n);
}
if (n != 0 && 0 <= n / n && n / n <= MAX && visited.count(n/n) == 0)
{
que.push({ n / n, temp + "/" });
visited.insert(n / n);
}
}
// 변환이 불가능한 경우 -1을 출력한다
cout << -1 << "\n";
return 0;
}
04-5 물통 ( 2251 )
- 각각 부피가 A, B, C(1≤A, B, C≤200) 리터인 세 개의 물통이 있다
- 처음에는 앞의 두 물통은 비어 있고, 세 번째 물통은 가득(C 리터) 차 있다
- 이제 어떤 물통에 들어있는 물을 다른 물통으로 쏟아 부을 수 있는데, 이때에는 한 물통이 비거나, 다른 한 물통이 가득 찰 때까지 물을 부을 수 있다
- 이 과정에서 손실되는 물은 없다고 가정한다
- 이와 같은 과정을 거치다보면 세 번째 물통(용량이 C인)에 담겨있는 물의 양이 변할 수도 있다
- 첫 번째 물통(용량이 A인)이 비어 있을 때, 세 번째 물통(용량이 C인)에 담겨있을 수 있는 물의 양을 모두 구해내는 프로그램을 작성하시오
// https://j2wooooo.tistory.com/130 이분은 push 이후 바로 방문처리 하게함
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
int a, b, c;
}node;
const int MAX = 201;
int CapacityA, CapacityB, CapacityC;
bool visited[MAX][MAX][MAX];
vector<int> answer;
void Input()
{
cin >> CapacityA >> CapacityB >> CapacityC;
}
void Solution()
{
// 필요한 변수 초기화
queue<node> que;
que.push({ 0, 0, CapacityC });
while (!que.empty())
{
// 다음 물높이 세팅
node cur = que.front();
int a = cur.a;
int b = cur.b;
int c = cur.c;
que.pop();
// 해당 물높이 방문 처리
if (visited[a][b][c] == true) continue;
visited[a][b][c] = true;
// 첫 번째 물통(용량이 A인)이 비어 있을 때, 세 번째 물통(용량이 C인)에 담겨있는 물의 양을 정답지에 넣는다
if (a == 0) answer.push_back(c);
// A물통에서 B물통으로 줄 때
if (CapacityB < a + b) que.push({ a + b - CapacityB, CapacityB, c });
else que.push({ 0, a + b, c });
// A물통에서 C물통으로 줄 때
if (CapacityC < a + c) que.push({ a + c - CapacityC, b, CapacityC });
else que.push({ 0, b, a + c });
// B물통에서 A물통으로 줄 때
if (CapacityA < b + a) que.push({ CapacityA, b + a - CapacityA, c });
else que.push({ b + a, 0, c });
// B물통에서 C물통으로 줄 때
if (CapacityC < b + c) que.push({ a, b + c - CapacityC, CapacityC });
else que.push({ a, 0, b + c });
// C물통에서 A물통으로 줄 때
if (CapacityA < c + a) que.push({ CapacityA, b, c + a - CapacityA });
else que.push({ c + a, b, 0 });
// C물통에서 B물통으로 줄 때
if (CapacityB < c + b) que.push({ a, CapacityB, c + b - CapacityB });
else que.push({ a, c + b, 0 });
}
sort(answer.begin(), answer.end());
for (int i = 0; i < answer.size(); i++)
{
cout << answer[i] << " ";
}
}
void Solve()
{
Input();
Solution();
}
int main(void)
{
ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
Solve();
return 0;
}
04-6 토마토 ( 7576 )
- 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라
#include <bits/stdc++.h>
using namespace std;
// 그래프 관련 변수
int n, m;
int graph[1001][1001];
queue<pair<int, int>> q;
// 상, 하, 좌, 우 이동
int dx[4] = { -1, 1, 0, 0 };
int dy[4] = { 0, 0, -1, 1 };
void bfs(void)
{
while (!q.empty())
{
// main에서 분명히 y 좌표를 first에 입력해놨다
int y = q.front().first;
int x = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || m <= nx || n <= ny) continue;
if (graph[ny][nx] == -1) continue;
if (graph[ny][nx] == 0)
{
q.push({ ny, nx });
graph[ny][nx] = graph[y][x] + 1;
}
}
}
}
int main()
{
// 입력받기
cin >> m >> n;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
scanf("%d", &graph[i][j]);
if (graph[i][j] == 1)
{
// 분명히 y 좌표를 first에 입력해놨다
q.push({ i, j });
}
}
}
// BFS를 통해 탐색
bfs();
// 안 익은 토마토 없나 확인
int result = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
result = max(result, graph[i][j] - 1);
if (graph[i][j] == 0)
{
cout << -1 << endl;
return 0;
}
}
}
// 결과 출력
printf("%d\n", result);
return 0;
}
04-7 경쟁적 전염 ( 18405 )
- 시험관의 크기와 바이러스의 위치 정보가 주어졌을 때, S초가 지난 후에 (X,Y)에 존재하는 바이러스의 종류를 출력하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
const int MAX = 202;
int arr[MAX][MAX];
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
struct Virus
{
int virus;
int x;
int y;
};
bool cmp(const Virus& v1, const Virus& v2)
{
return v1.virus < v2.virus;
}
int main()
{
vector<Virus> vec;
int N, K;
cin >> N >> K;
for (int y = 0; y < N; y++)
{
for (int x = 0; x < N; x++)
{
cin >> arr[y][x];
vec.push_back({ arr[y][x], x, y });
}
}
int S, X, Y;
cin >> S >> Y >> X;
int s = 0;
sort(vec.begin(), vec.end(), cmp);
while (s < S)
{
int len = vec.size();
for (int j = 0; j < len; j++)
{
Virus v = vec[j];
for (int i = 0; i < 4; i++)
{
int nx = v.x + dx[i];
int ny = v.y + dy[i];
if (nx < 0 || ny < 0 || N <= nx || N <= ny) continue;
if (arr[ny][nx] == 0)
{
arr[ny][nx] = v.virus;
vec.push_back({ arr[ny][nx], nx, ny });
}
}
}
if (0 < arr[Y - 1][X - 1]) break;
s++;
}
cout << arr[Y - 1][X - 1];
return 0;
}
04-8 숨바꼭질 4 ( 13913 )
- 수빈이와 동생의 위치가 주어졌을 때, 수빈이가 동생을 찾을 수 있는 가장 빠른 시간이 몇 초 후인지 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
#define max 1000001
int N, K;
int parent[max];
bool visited[max];
// 현재 위치와 걸린 시간
struct node
{
int cur;
int time;
};
void bfs(int start)
{
queue<node> q;
q.push({ start, 0 });
visited[start] = true;
while (!q.empty())
{
int cur = q.front().cur;
int time = q.front().time;
q.pop();
// 목적지 도착 하면 종료
if (cur == K)
{
cout << time << endl;
return;
}
// 해당 지점을 처음 방문하는 경우 부모 설정 및 방문 처리
if (0 <= cur - 1)
{
if (!visited[cur - 1])
{
q.push({ cur - 1, time + 1 });
visited[cur - 1] = true;
parent[cur - 1] = cur;
}
}
if (cur + 1 < max)
{
if (!visited[cur + 1])
{
q.push({ cur + 1, time + 1 });
visited[cur + 1] = true;
parent[cur + 1] = cur;
}
}
if (cur * 2 < max)
{
if (!visited[cur * 2])
{
q.push({ cur * 2, time + 1 });
visited[cur * 2] = true;
parent[cur * 2] = cur;
}
}
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0);
cin >> N >> K;
bfs(N);
stack<int> stk;
stk.push(K);
int cur = K;
while (cur != N)
{
stk.push(parent[cur]);
cur = stk.top();
}
while (!stk.empty())
{
cout << stk.top() << ' ';
stk.pop();
}
return 0;
}
04-9 이모티콘 ( 14226 )
- 영선이가 S개의 이모티콘을 화면에 만드는데 걸리는 시간의 최솟값을 구하는 프로그램을 작성하시오
// https://junbastick.tistory.com/17 참고
#include<iostream>
#include<vector>
#include<queue>
#define endl "\n"
using namespace std;
#define MAX 1001
bool visit[MAX][MAX];
int BFS(int S)
{
queue<pair<pair<int, int>, int>> q;
q.push(make_pair(make_pair(1, 0), 0));
visit[1][0] = true;
while (!q.empty())
{
int screen = q.front().first.first;
int clip = q.front().first.second;
int time = q.front().second;
q.pop();
// 각 시간대 별로 현재 상황을 사진 찍어놓는다는 느낌
if (screen == S)
return time;
if (!visit[screen][screen])
{
q.push(make_pair(make_pair(screen, screen), time + 1));
visit[screen][screen] = true;
}
if (screen + clip <= S && !visit[screen + clip][clip])
{
q.push(make_pair(make_pair(screen + clip, clip), time + 1));
visit[screen + clip][clip] = true;
}
if (2 <= screen - 1 && !visit[screen - 1][clip])
{
q.push(make_pair(make_pair(screen - 1, clip), time + 1));
visit[screen - 1][clip] = true;
}
}
}
void Answer()
{
int S;
cin >> S;
cout << BFS(S) << endl;
}
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
Answer();
return 0;
}
#include <bits/stdc++.h>
using namespace std;
//1개는 이미 입력
int S;
int visited[3000][3000];
int main()
{
cin >> S;
//현재 상태, 클립보드에 저장된 개수
queue<pair<int, int>> q;
q.push({ 1,0 });
visited[1][0] = 1;
while (!q.empty())
{
auto cur = q.front();
q.pop();
int now = cur.first;
int clip = cur.second;
//체크
if (now == S)
{
cout << visited[now][clip] - 1 << '\n';
break;
}
//1.복사
int nextClip = now;
if (visited[now][nextClip] == 0)
{
q.push({ now, nextClip });
visited[now][nextClip] = visited[now][clip] + 1;
}
//2.붙여넣기
if (now + clip <= S)
{
if (visited[now + clip][clip] == 0)
{
q.push({ now + clip, clip });
visited[now + clip][clip] = visited[now][clip] + 1;
}
}
//3.삭제
if (now > 0)
{
if (visited[now - 1][clip] == 0)
{
q.push({ now - 1, clip });
visited[now - 1][clip] = visited[now][clip] + 1;
}
}
}
return 0;
}
04-10 알고스팟 ( 1261 )
- 현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
#define MAX 1e9
int N, M;
int board[101][101];
int dist[101][101];
int dx[] = { 1, -1, 0, 0 };
int dy[] = { 0, 0, 1, -1 };
void bfs()
{
queue<pair<int, int>> q;
q.push({ 0,0 });
dist[0][0] = 0;
while (!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || M <= nx || N <= ny) continue;
if (board[ny][nx] == 0)
{
// 이 경우가 성립한다면 벽을 부술 필요가
// 없는데 부순애가 지나갔다는 의미
if (dist[y][x] < dist[ny][nx])
{
dist[ny][nx] = dist[y][x];
q.push({ nx,ny });
}
}
else if (board[ny][nx] == 1)
{
// 이 경우가 성립하다면 벽을 더 적게
// 부수고 지나갈수 있다는 의미
if (dist[y][x] + 1 < dist[ny][nx])
{
dist[ny][nx] = dist[y][x] + 1;
q.push({ nx,ny });
}
}
}
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> M >> N;
string str;
for (int i = 0; i < N; i++)
{
cin >> str;
for (int j = 0; j < M; j++)
{
dist[i][j] = MAX;
board[i][j] = str[j] - '0';
}
}
bfs();
cout << dist[N - 1][M - 1] << "\n";
return 0;
}
Chapter 05 그래프
05-1 ABCDE ( 13023 )
- 위와 같은 친구 관계가 존재하는지 안하는지 구하는 프로그램을 작성하시오
// 기본 그래프 문제 3개
// 다익스트라 문제 3개, 참고로 다익스트라는 DP의 일종이다
// 플로이드 워셜 문제 3개
// 유니온 파인드 문제 3개
#include<bits/stdc++.h>
using namespace std;
vector<int> people[2000];
bool visited[2000];
bool ispossible;
void dfs(int node, int depth)
{
if (depth == 4)
{
ispossible = true;
return;
}
visited[node] = true;
for (int i = 0; i < people[node].size(); ++i)
{
int next = people[node][i];
// if(!visited[next] && ispossible == false) 이렇게 하면 좀더 최적화 된다
if (!visited[next])
dfs(next, depth + 1);
}
visited[node] = false;
}
int N, M;
int main()
{
cin >> N >> M;
for (int i = 0; i < M; ++i)
{
int a, b;
cin >> a >> b;
people[a].push_back(b);
people[b].push_back(a);
}
for (int i = 0; i < N; ++i)
{
dfs(i, 0);
if (ispossible) break;
}
cout << ispossible << '\n';
}
05-2 DFS와 BFS ( 1260 )
- 그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
vector<int> vec[1001];
queue<int> Q;
int chDFS[1001], chBFS[1001], N;
void DFS(int v)
{
cout << v << " ";
chDFS[v] = 1;
for (int i = 0; i < vec[v].size(); i++)
{
int next = vec[v][i];
if (!chDFS[next])
{
DFS(next);
}
}
}
void BFS(int v)
{
Q.push(v);
chBFS[v] = 1;
while (!Q.empty())
{
int cur = Q.front();
Q.pop();
cout << cur << " ";
for (int i = 0; i < vec[cur].size(); i++)
{
int next = vec[cur][i];
if (!chBFS[next])
{
Q.push(next);
chBFS[next] = 1;
}
}
}
}
int main()
{
int M, V, a, b;
cin >> N >> M >> V;
while (M--)
{
cin >> a >> b;
vec[a].push_back(b);
vec[b].push_back(a);
}
for (int i = 1; i <= N; i++)
sort(vec[i].begin(), vec[i].end());
DFS(V);
cout << "\n";
BFS(V);
}
05-3 연결 요소의 개수 ( 11724 )
- 방향 없는 그래프가 주어졌을 때, 연결 요소 (Connected Component)의 개수를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
vector<int> vect[1001]; //인접리스트
bool visited[1001]; //방문기록
int N, M;
/* DFS : 방문기록 남기는 용도 */
void DFS(int vertex)
{
visited[vertex] = true;
for (int i = 0; i < vect[vertex].size(); i++) //최댓값 주의 : 벡터 그 원소에 해당하는 크기만큼 돌아야함
{
int idx = vect[vertex][i];
if (!visited[idx])
{
DFS(idx);
}
}
}
int main()
{
int u, v;
int cnt = 0;
cin >> N >> M;
for (int i = 0; i < M; i++)
{
cin >> u >> v;
vect[u].push_back(v);
vect[v].push_back(u); //무방향 그래프이기 때문
}
for (int i = 1; i <= N; i++) //빠짐없이 탐색하기 위해
{
if (!visited[i])
{
cnt++;
DFS(i);
}
}
cout << cnt << "\n";
}
05-4 이분 그래프 ( 1707 )
- 그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
#define RED 2
#define BLUE 3
vector<int> vect[20001]; //인접리스트
int visited[20001]; //방문기록
int V, E;
/* DFS 실행 */
void DFS(int start)
{
//방문안한 점이면 RED
if (visited[start] == 0)
visited[start] = RED;
//연결된 점들 방문
for (int i = 0; i < vect[start].size(); i++)
{
int idx = vect[start][i];
if (visited[idx] == 0) //방문 안한 점이면
{
//요소에 방문기록 남김(색칠하기)
if (visited[start] == RED)
visited[idx] = BLUE;
else if (visited[start] == BLUE)
visited[idx] = RED;
//요소별로 방문
DFS(idx);
}
}
}
/* 이분그래프 검사 */
int check()
{
//인접한 노드와 색이 같으면 이분그래프 X
for (int i = 1; i <= V; i++)
{
//연결된게 자기자신 뿐일 경우엔 size가 0이라서 돌아가지 않는다.
for (int j = 0; j < vect[i].size(); j++)
{
int idx = vect[i][j];
if (visited[i] == visited[idx])
{
return false;
}
}
}
return true;
}
int main()
{
int T; //테스트케이스
int u, v; //노드 담을 변수
cin >> T;
while (T--)
{
cin >> V >> E;
for (int i = 0; i < E; i++)
{
cin >> u >> v;
vect[u].push_back(v);
vect[v].push_back(u);
}
//빠짐없이 방문하기 위해 1부터 원소 개수까지 다 방문해봄
for (int i = 1; i <= V; i++)
{
if (visited[i] == 0)
DFS(i);
}
if (check() == 0) //이분그래프인지 검사
cout << "NO\n";
else
cout << "YES\n";
memset(visited, 0, sizeof(visited));
memset(vect, 0, sizeof(vect));
}
}
// https://hongjw1938.tistory.com/117 이분 그래프 설명
#include<bits/stdc++.h>
using namespace std;
#define RED 1
#define BLUE 2
vector<int> vect[20001];
int visited[20001];
int V, E;
void BFS(int start)
{
queue<int> q;
q.push(start);
visited[start] = RED;
while (!q.empty()) //큐가 빌 때 까지 반복(전체)
{
int now = q.front();
q.pop();
for (int i = 0; i < vect[now].size(); i++)
{
int next = vect[now][i];
if (visited[next] == 0)
{
q.push(next);
if (visited[now] == RED) visited[next] = BLUE;
else if (visited[now] == BLUE) visited[next] = RED;
}
}
}
}
bool check()
{
for (int i = 1; i <= V; i++)
{
for (int j = 0; j < vect[i].size(); j++)
{
int next = vect[i][j];
if (visited[i] == visited[next])
return false;
}
}
return true;
}
int main()
{
int K, u, v;
cin >> K;
while (K--)
{
cin >> V >> E;
for (int i = 0; i < E; i++)
{
cin >> u >> v;
vect[u].push_back(v);
vect[v].push_back(u);
}
//빠짐없이 방문하기 위해 노드 개수만큼 BFS 돌려줘야함
for (int i = 1; i <= V; i++)
{
if (visited[i] == 0)
{
BFS(i);
}
}
//이분그래프 검사
if (check())
cout << "YES\n";
else
cout << "NO\n";
memset(visited, 0, sizeof(visited));
memset(vect, 0, sizeof(vect));
}
}
05-5 단지번호붙이기 ( 2667 )
- 지도를 입력하여 단지수를 출력하고, 각 단지에 속하는 집의 수를 오름차순으로 정렬하여 출력하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
#define MAX 26
int n, cnt = 0;
string arr[MAX];
bool visited[MAX][MAX] = { 0 };
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
queue<pair<int, int>> q;
vector<int> result;
void bfs(int x, int y)
{
q.push({ x,y });
visited[y][x] = true;
while (!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
cnt++;
for (int i = 0; i < 4; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || n <= nx || n <= ny) continue;
if (visited[ny][nx] == false && arr[ny][nx] == '1')
{
q.push({ nx,ny });
visited[ny][nx] = true;
}
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> arr[i];
for (int y = 0; y < n; y++)
{
for (int x = 0; x < n; x++)
{
if (arr[y][x] == '1' && visited[y][x] == false)
{
cnt = 0;
bfs(x, y);
result.push_back(cnt);
}
}
}
sort(result.begin(), result.end());
cout << result.size() << "\n";
for (int i = 0; i < result.size(); i++)
{
cout << result[i] << "\n";
}
}
05-6 미로 탐색 ( 2178 )
- 미로가 주어졌을 때, (1, 1)에서 출발하여 (N, M)의 위치로 이동할 때 지나야 하는 최소의 칸 수를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
int main()
{
vector<vector<int>> board(110, vector<int>(110, 0));
vector<vector<bool>> visited(110, vector<bool>(110, false));
int N, M;
cin >> N >> M;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
scanf("%1d", &board[i][j]);
}
}
queue<pair<pair<int, int>, int>> que;
que.push(make_pair(make_pair(0, 0), 1));
visited[0][0] = true;
while (!que.empty())
{
int x = que.front().first.first;
int y = que.front().first.second;
int count = que.front().second;
que.pop();
if (x == M - 1 && y == N - 1)
{
cout << count << endl;
return 0;
}
for (int i = 0; i < 4; ++i)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || M <= nx || N <= ny) continue;
if (visited[ny][nx] == false && board[ny][nx] == 1)
{
que.push(make_pair(make_pair(nx, ny), count + 1));
visited[ny][nx] = true;
}
}
}
}
05-7 특정 거리의 도시 찾기 ( 18352 )
- 이 때 특정한 도시 X로부터 출발하여 도달할 수 있는 모든 도시 중에서, 최단 거리가 정확히 K인 모든 도시들의 번호를 출력하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
vector<int> answer;
const int MAX = 300001;
void getCityCount(vector<vector<int>>& graph, vector<bool>& visited, int node, int target_distance)
{
// 필요한 변수 초기화
queue<pair<int,int>> que;
que.push(make_pair(node, 0));
visited[node] = true;
while(!que.empty())
{
// 다음 위치 세팅
int cur = que.front().first;
int distance = que.front().second;
que.pop();
// 원하는 거리의 도시이면 정답지에 넣는다
if(distance == target_distance) answer.push_back(cur);
// 현재 노드에서 방문할 수 있는 노드를 모두 큐에 담는다
for(auto next : graph[cur])
{
if(visited[next]) continue;
que.push(make_pair(next, distance + 1));
visited[next] = true;
}
}
}
int main()
{
int N = 0, M = 0, K = 0, X = 0;
cin >> N >> M >> K >> X;
// https://leeeegun.tistory.com/m/3 참고
vector<vector<int>> graph(N+1);
vector<bool> visited(MAX, false);
for(int i = 0; i < M; ++i)
{
int from = 0, to = 0;
cin >> from >> to;
graph[from].push_back(to);
}
getCityCount(graph, visited, X, K);
if(answer.size() == 0)
{
cout << -1 << endl;
}
else
{
sort(answer.begin(), answer.end());
for(auto value : answer)
{
cout << value << endl;
}
}
}
05-8 나이트의 이동 ( 7562 )
- 나이트는 몇 번 움직이면 이 칸으로 이동할 수 있을까?
#include <bits/stdc++.h>
using namespace std;
int dx[] = { -2, -2, -1, -1, 1, 1, 2, 2 };
int dy[] = { 1, -1, 2, -2, 2, -2, 1, -1 };
int graph[301][301];
bool visited[301][301];
int bfs(int size, int beginX, int beginY, int endX, int endY)
{
queue<pair<int, int>> q;
q.push(make_pair(beginX, beginY));
visited[beginY][beginX] = true;
while (!q.empty())
{
int x = q.front().first;
int y = q.front().second;
q.pop();
if (x == endX && y == endY) return graph[y][x];
for (int i = 0; i < 8; i++)
{
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0 || ny < 0 || size <= nx || size <= ny) continue;
// 이전으로 되돌아 갔는데 목적지와 오히려 가까워 질수는 없다는 것을 명심
if (!visited[ny][nx])
{
q.push(make_pair(nx, ny));
graph[ny][nx] = graph[y][x] + 1;
visited[ny][nx] = true;
}
}
}
}
int main(void)
{
int n, m;
int beginX, beginY;
int endX, endY;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> m;
memset(visited, 0, sizeof(visited));
memset(graph, 0, sizeof(graph));
cin >> beginX >> beginY >> endX >> endY;
cout << bfs(m, beginX, beginY, endX, endY) << endl;
}
}
05-9 경로 찾기 ( 11403 )
- 가중치 없는 방향 그래프 G가 주어졌을 때, 모든 정점 (i, j)에 대해서, i에서 j로 가는 경로가 있는지 없는지 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
const int MAX = 101;
void floyd(vector<vector<int>>& graph, int N)
{
for(int k = 0; k < N; ++k)
{
for(int x = 0; x < N; ++x)
{
for(int nx = 0; nx < N; ++nx)
{
// x에서 nx로 가는 길이 없어도 k를 거쳐갈 수 있으면 갈 수 있다고 여긴다
if(graph[x][k] && graph[k][nx])
graph[x][nx] = 1;
}
}
}
}
int main()
{
vector<vector<int>> graph(MAX, vector<int>(MAX, 0));
int N;
cin >> N;
for(int x = 0; x < N; ++x)
{
for(int nx = 0; nx < N; ++nx)
{
cin >> graph[x][nx];
}
}
floyd(graph, N);
for(int x = 0; x < N; ++x)
{
for(int nx = 0; nx < N; ++nx)
{
cout << graph[x][nx] << " ";
}
cout << endl;
}
}
05-10 Two Dots ( 16929 )
- 게임판의 상태가 주어졌을 때, 사이클이 존재하는지 아닌지 구해보자
#include<bits/stdc++.h>
using namespace std;
int N, M;
char board[51][51];
bool visited[51][51];
const int dy[4] = { 0, 0, 1, -1 };
const int dx[4] = { 1, -1, 0, 0 };
bool search(int row, int col, int brow, int bcol, char alp)
{
if (visited[row][col]) return true;
visited[row][col] = true;
bool ret = false;
for (int k = 0; k < 4; ++k)
{
int ny = row + dy[k];
int nx = col + dx[k];
if (!(0 <= ny && ny < N && 0 <= nx && nx < M)) continue;
if (ny == brow && nx == bcol) continue;
if (alp != board[ny][nx]) continue;
ret = ret + search(ny, nx, row, col, alp);
}
return ret;
}
int main()
{
cin >> N >> M;
for (int row = 0; row < N; ++row)
for (int col = 0; col < M; ++col)
cin >> board[row][col];
for (int row = 0; row < N; ++row)
for (int col = 0; col < M; ++col)
{
if (visited[row][col]) continue;
if (search(row, col, -1, -1, board[row][col]))
{
cout << "Yes" << "\n";
return 0;
}
}
cout << "No" << "\n";
return 0;
}
05-11 네트워크 연결 ( 1922 )
- 각 컴퓨터를 연결하는데 필요한 비용이 주어졌을 때 모든 컴퓨터를 연결하는데 필요한 최소비용을 출력하라
// https://velog.io/@y00913/%EB%B0%B1%EC%A4%80-1922-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%97%B0%EA%B2%B0-C 참고
// https://ongveloper.tistory.com/284 프림 기반
// https://jaimemin.tistory.com/802 우선순위큐 기반
#include<bits/stdc++.h>
using namespace std;
int N, M, res = 0;
int parent[1001];
vector<pair<int, pair<int, int>>> v;
int findParent(int a)
{
if (parent[a] == a) return a;
else return parent[a] = findParent(parent[a]);
}
void unionParent(int a, int b)
{
a = findParent(a);
b = findParent(b);
if (a != b) parent[b] = a;
}
bool sameParent(int a, int b)
{
a = findParent(a);
b = findParent(b);
if (a == b) return true;
else return false;
}
void solution()
{
sort(v.begin(), v.end());
for (int i = 1; i <= N; i++)
parent[i] = i;
for (int i = 0; i < M; i++)
{
int a = v[i].second.first;
int b = v[i].second.second;
int cost = v[i].first;
if (!sameParent(a, b))
{
unionParent(a, b);
res += cost;
}
}
cout << res;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> N;
cin >> M;
for (int i = 0; i < M; i++)
{
int a, b, c;
cin >> a >> b >> c;
v.push_back({ c, {a, b} });
}
solution();
return 0;
}
05-12 여행 가자 ( 1976 )
- 동혁이의 여행 일정이 주어졌을 때, 이 여행 경로가 가능한 것인지 알아보자
// https://dmsvk01.tistory.com/112 플로이드 워셜
// 아래 풀이법은 Union Find 기법
#include<bits/stdc++.h>
using namespace std;
int N, M;
int root[201];
int find(int node)
{
if (root[node] == node) return node;
return root[node] = find(root[node]);
}
void exeunion(int a, int b)
{
a = find(a);
b = find(b);
if (a < b) root[b] = a;
else root[a] = b;
}
int main()
{
cin >> N;
cin >> M;
for (int i = 1; i <= N; i++) root[i] = i;
for (int i = 1; i <= N; i++)
{
for (int j = 1; j <= N; j++)
{
int temp;
cin >> temp;
if (temp == 1) exeunion(i, j);
}
}
bool is_possible = true;
int temp;
cin >> temp;
int rootnode = find(temp);
for (int i = 0; i < M - 1; i++)
{
int node;
cin >> node;
if (rootnode != find(node)) is_possible = false;
}
if (is_possible) cout << "YES\n";
else cout << "NO\n";
return 0;
}
05-13 게리맨더링 ( 17471 )
- 백준시의 정보가 주어졌을 때, 인구 차이의 최솟값을 구해보자
// https://torbjorn.tistory.com/242 참고
05-14 지름길 (1446)
- 세준이가 운전해야 하는 거리의 최솟값을 출력하시오
// https://velog.io/@minayeah/C-%EB%B0%B1%EC%A4%80-1446-%EC%A7%80%EB%A6%84%EA%B8%B8 참고
#include<bits/stdc++.h>
using namespace std;
const int INF = 10005;
int N, D;
int from, to, cost;
vector<int> m(10005, INF);
vector<pair<int, int>> v[10005];
int main()
{
cin >> N >> D;
for (int i = 0; i < N; i++)
{
cin >> from >> to >> cost;
if (to > D || to - from < cost) continue;
v[to].push_back({ from, cost });
}
m[0] = 0;
for (int i = 1; i <= D; i++)
{
m[i] = m[i - 1] + 1;
for (int j = 0; j < (int)v[i].size(); j++)
{
m[i] = min(m[i], m[v[i][j].first] + v[i][j].second);
}
}
cout << m[D];
}
05-15 완전 이진 트리 ( 9934 )
- 상근이가 종이에 적은 순서가 모두 주어졌을 때, 각 레벨에 있는 빌딩의 번호를 구하는 프로그램을 작성하시오
// https://conkjh032.tistory.com/323 참고
05-16 일루미네이션 ( 5547 )
- 상근이네 집의 건물 위치 지도가 주어졌을 때, 조명을 장식할 벽면의 길이의 합을 구하는 프로그램을 작성하시오
// https://yy-03-10.tistory.com/61 참고
#include<bits/stdc++.h>
using namespace std;
int ody[] = { -1,-1,0,0,1,1 };
int odx[] = { 0,1,-1,1,0,1 };
int edy[] = { -1,-1,0,0,1,1 };
int edx[] = { -1,0,1,-1,-1,0 };
int W, H;
int map[102][102];
int chk[102][102];
int answer = 0;
queue<pair<int, int>> inblock;
void Input()
{
cin >> W >> H;
for (int i = 0; i < H; i++)
{
for (int j = 0; j < W; j++)
{
cin >> map[i][j];
}
}
}
int Solution(int y, int x)
{
int sum = 0;
for (int i = 0; i < 6; i++)
{
if (y % 2 == 0)
{
int ny = y + ody[i];
int nx = x + odx[i];
if (ny < 0 || nx < 0 || ny >= H || nx >= W || map[ny][nx] == 2)
sum++;
}
else
{
int ny = y + edy[i];
int nx = x + edx[i];
if (ny < 0 || nx < 0 || ny >= H || nx >= W || map[ny][nx] == 2)
sum++;
}
}
return sum;
}
void Outblock(int y, int x)
{
chk[y][x] = true;
map[y][x] = 2;
queue<pair<int, int>> q;
q.push(make_pair(y, x));
while (!q.empty())
{
int y = q.front().first;
int x = q.front().second;
q.pop();
for (int i = 0; i < 6; i++)
{
int ny = (y % 2) ? y + edy[i] : y + ody[i];
int nx = (y % 2) ? x + edx[i] : x + odx[i];
if (ny < 0 || ny >= H || nx < 0 || nx >= W)
continue;
if (map[ny][nx] == 0 && !chk[ny][nx])
{
chk[ny][nx] = true;
map[ny][nx] = 2;
q.push(make_pair(ny, nx));
}
}
}
}
int main()
{
Input();
for (int i = 0; i < H; i++)
{
for (int j = 0; j < W; j++)
{
if (map[i][j] == 0 && (i == 0 || i == H - 1 || j == 0 || j == W - 1) && !chk[i][j]) {
Outblock(i, j);
}
}
}
for (int i = 0; i < H; i++)
{
for (int j = 0; j < W; j++)
{
if (map[i][j] == 1)
{
answer += Solution(i, j);
}
}
}
cout << answer << "\n";
}
05-17 숫자고르기 ( 2268 )
- 이러한 조건을 만족시키도록 정수들을 뽑되, 최대로 많이 뽑는 방법을 찾는 프로그램을 작성하시오
// https://chosh95.tistory.com/456 참고
Chapter 06 슬라이딩 윈도우, 투 포인터
06-1 귀여운 라이언 ( 15565 )
- 꿀귀 라이언 인형과, 마찬가지로 꿀귀인 어피치 인형이 N개 일렬로 놓여 있다. 라이언 인형은 1, 어피치 인형은 2로 표현하자 라이언 인형이 K개 이상 있는 가장 작은 연속된 인형들의 집합의 크기를 구하여라
#include<bits/stdc++.h>
using namespace std;
int N, K;
vector<int> pos;
int main()
{
int currentDoll;
cin >> N >> K;
for (int i = 0; i < N; ++i)
{
cin >> currentDoll;
if (currentDoll == 1)
pos.push_back(i);
}
if (pos.size() < K)
{
cout << -1 << endl;
return 0;
}
int ans = 1e9;
// size가 5 K가 3이라고 가정하고 상상해 보자
for (int i = 0; i <= pos.size() - K; ++i)
{
ans = min(ans, pos[i + K - 1] - pos[i] + 1);
}
cout << ans << endl;
}
06-2 수 고르기 ( 2230 )
- N개의 정수로 이루어진 수열 A[1], A[2], …, A[N]이 있다 이 수열에서 두 수를 골랐을 때(같은 수일 수도 있다), 그 차이가 M 이상이면서 제일 작은 경우를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
// MAX가 1e9면 안된다는것 주의
#define MAX 2000000000
int main()
{
int answer = MAX;
int n = 0, target = 0;
cin >> n >> target;
vector<int> vecNumber(n, 0);
for (int i = 0; i < n; ++i)
cin >> vecNumber[i];
sort(vecNumber.begin(), vecNumber.end());
// target이 0이라면 start가 OutOfBounds를 유발할 수 있다
int start = 0, end = 0;
while (start < n && end < n)
{
if (vecNumber[end] - vecNumber[start] < target)
end = end + 1;
else
{
answer = min(answer, vecNumber[end] - vecNumber[start]);
start = start + 1;
}
}
cout << answer << endl;
}
06-3 겹치는 건 싫어 (20922)
- 이 수열에서 같은 정수를 K개 이하로 포함한 최장 연속 부분 수열의 길이를 구하는 프로그램을 작성해보자
#include<bits/stdc++.h>
#define AMAX 200001
#define DMAX 100001
using namespace std;
int arr[AMAX];
int dup[DMAX];
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
}
int answer = 0;
int left = 1;
int right = 1;
while (left <= n && right <= n)
{
if (dup[arr[right]] < k)
{
dup[arr[right]]++;
answer = max(answer, right - left + 1);
right = right + 1;
}
else
{
dup[arr[left]]--;
left = left + 1;
}
}
cout << answer;
return 0;
}
06-4 두 용액 ( 2470 )
- 산성 용액과 알칼리성 용액의 특성값이 주어졌을 때, 이 중 두 개의 서로 다른 용액을 혼합하여 특성값이 0에 가장 가까운 용액을 만들어내는 두 용액을 찾는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<int> ans(2);
int start = 0, end = n - 1, min = 2000000001;
int arr[n];
for (int i = 0; i < n; i++) cin >> arr[i];
sort(arr, arr + n);
while (start < end)
{
int sum = arr[start] + arr[end];
if (abs(sum) < abs(min))
{
ans[0] = arr[start];
ans[1] = arr[end];
min = sum;
}
if (sum < 0) start++;
else end--;
}
sort(ans.begin(), ans.end());
for (int i = 0; i < ans.size(); i++) cout << ans[i] << " ";
return 0;
}
06-5 회전 초밥 ( 2531 )
- 손님이 먹을 수 있는 초밥 가짓수의 최댓값을 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int N, d, k, c;
int dish, cnt, coupon, maxi = 0;
int sushi[300001];
int check[3001];
vector<int> eat;
int main()
{
// N:접시수 d:초밥종류수 k:연속접시 C:쿠폰번호
cin >> N >> d >> k >> c;
// 회전벨트 위 초밥
for (int i = 0; i < N; i++) cin >> sushi[i];
// 슬라이딩 윈도우
for (int i = 0; i < N; i++)
{
dish = 0; // 중복된 스시 체크
coupon = 1; // 쿠폰 스시가 있는지 확인
for (int j = i; j < i + k; j++)
{
if (check[sushi[j % N]] == 1) dish++; // 이미 먹은 초밥일 경우 중복 수 표시
else check[sushi[j % N]] = 1; // 처음 먹어보는 초밥일 경우 체크
if (sushi[j % N] == c) coupon = 0; // 쿠폰 스시 있을 시
}
maxi = max(maxi, k - dish + coupon); //연속으로 먹을 수 있는 최대접시 - 중복접시 + 쿠폰스시
memset(check, 0, sizeof(check)); // 체크 초기화
}
cout << maxi;
}
06-6 가장 긴 짝수 연속한 부분 수열 (large) ( 22862 )
- 수열 S에서 최대 K번 원소를 삭제한 수열에서 짝수로 이루어져 있는 연속한 부분 수열 중 가장 긴 길이를 구해보자
#include <bits/stdc++.h>
using namespace std;
int seq[1000010];
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
int n, k; cin >> n >> k;
for (int i = 0; i < n; i++) cin >> seq[i];
int st = 0, en = 0;
int cnt = (seq[st] & 1) ? 1 : 0;
int m = 0;
while (st < n && en < n)
{
while (en < n - 1)
{
if (seq[en + 1] & 1)
{
if (cnt < k) cnt++;
else break;
}
en++;
}
m = max(m, en - st + 1 - cnt);
if (seq[st] & 1) cnt--;
st++;
}
cout << m;
}
#include <bits/stdc++.h>
using namespace std;
int main()
{
int result = 0;
int numCount, maxDeleteCnt;
cin >> numCount >> maxDeleteCnt;
vector<int> numbers;
int input;
for (int i = 0; i < numCount; i++)
{
cin >> input;
numbers.push_back(input);
}
int currentDeleteCnt = 0;
int currentLen = 0;
int left = 0;
int right = 0;
while (right < numCount)
{
if (numbers[right] % 2 == 0)
{
currentLen++;
right++;
result = max(result, currentLen - currentDeleteCnt);
}
else
{
if (currentDeleteCnt + 1 <= maxDeleteCnt)
{
currentDeleteCnt++;
currentLen++;
result = max(result, currentLen - currentDeleteCnt);
right++;
}
else
{
if (right > left)
{
if (numbers[left] % 2 == 1) currentDeleteCnt--;
left++;
currentLen--;
}
else
{
left++;
right++;
}
}
}
}
cout << result;
return 0;
}
06-7 좋다 ( 1253 )
- N개의 수가 주어지면 그 중에서 좋은 수의 개수는 몇 개인지 출력하라
#include<bits/stdc++.h>
using namespace std;
int N;
long long num[2010];
int Left, Right;
int ans;
int main(void)
{
cin >> N;
for (int i = 1; i <= N; i++)
{
cin >> num[i];
}
sort(num + 1, num + N + 1);
for (int i = 1; i <= N; i++)
{
long long find = num[i];
Left = 1;
Right = N;
// 투포인터 알고리즘 활용
while (Left < Right)
{
if (num[Left] + num[Right] == find)
{
if (Left == i) Left++;
else if (Right == i) Right--;
else
{
ans++;
break;
}
}
else if (num[Left] + num[Right] < find) Left++;
else Right--;
}
}
cout << ans;
return 0;
}
06-8 부분합 ( 1806 )
- 이 수열에서 연속된 수들의 부분합 중에 그 합이 S 이상이 되는 것 중, 가장 짧은 것의 길이를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
#define MAX 1e9
int arr[100000];
int main()
{
int N, S;
cin >> N >> S;
for (int i = 0; i < N; i++)
{
cin >> arr[i];
}
int right = 0;
int left = 0;
int sum = arr[0];
int minlength = MAX;
while (left < N && right < N)
{
// 합이 크면 왼쪽 최소길이 갱신하고 움직이기
if (S <= sum)
{
int length = right - left + 1;
minlength = min(minlength, length);
sum = sum - arr[left];
left++;
}
// 합이 작으면 오른쪽 움직이기
else
{
right++;
sum = sum + arr[right];
}
}
// 조건 만족할 수 없으면 0
if (minlength == MAX)
{
minlength = 0;
}
cout << minlength;
return 0;
}
06-9 용액 합성하기 ( 14921 )
- 이 중 두 개의 용액을 혼합하여 만들 수 있는 0에 가장 가까운 특성값 B를 출력하시오
#include<bits/stdc++.h>
#define MAX 100000
using namespace std;
int a[MAX];
int answer = 200000000;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int left = 0;
int right = n - 1;
sort(a, a + n);
while (left < right)
{
// 두 용액 혼합
int sum = a[left] + a[right];
// 0에 더 가까우면 업데이트
if (abs(sum) < abs(answer))
{
answer = sum;
}
if (sum == 0)
break;
else if (sum < 0)
left++;
else
right--;
}
cout << answer;
return 0;
}
06-10 고냥이 ( 16472 )
- 문자열이 주어졌을 때 이 번역기가 인식할 수 있는 최대 문자열의 길이는 얼마인지가 궁금해졌다
#include<bits/stdc++.h>
using namespace std;
int alpha[26];
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int num, len, result = 0;
string str;
cin >> num >> str;
len = str.size();
int l = 0, r = 0, cnt = 0;
while (l < len && r < len)
{
while (cnt <= num && r < len)
{
int idx = str[r++] - 'a';
alpha[idx]++;
if (alpha[idx] == 1) cnt++;
if (cnt <= num) result = max(result, r - l);
}
while (num < cnt && l < len)
{
int idx = str[l++] - 'a';
alpha[idx]--;
if (alpha[idx] == 0) cnt--;
}
}
cout << result;
return 0;
}
Chapter 07 시뮬레이션
07-1 배열 돌리기 3 ( 16935 )
- 입력으로 주어진 배열에 R개의 연산을 순서대로 수행한 결과를 출력한다
#include<bits/stdc++.h>
using namespace std;
int n, m, r;
void one(vector<vector<int>>& vecArray)
{
for (int i = 0; i < n / 2; ++i)
for (int j = 0; j < m; ++j)
swap(vecArray[i][j], vecArray[n - 1 - i][j]);
}
void two(vector<vector<int>>& vecArray)
{
for (int i = 0; i < n; ++i)
for (int j = 0; j < m / 2; ++j)
swap(vecArray[i][j], vecArray[i][m - 1 - j]);
}
void three(vector<vector<int>>& vecArray)
{
vector<vector<int>> temp(100, vector<int>(100, 0));
int h = n;
swap(n, m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
temp[i][j] = vecArray[h - 1 - j][i];
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
vecArray[i][j] = temp[i][j];
}
void four(vector<vector<int>>& vecArray)
{
vector<vector<int>> temp(100, vector<int>(100, 0));
int w = m;
swap(n, m);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
temp[i][j] = vecArray[j][w - 1 - i];
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
vecArray[i][j] = temp[i][j];
}
void five(vector<vector<int>>& vecArray)
{
vector<vector<int>> temp(100, vector<int>(100, 0));
int N = n / 2;
int M = m / 2;
// 1 -> 2
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i][j + M] = vecArray[i][j];
}
// 2 -> 3
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i + N][j + M] = vecArray[i][j + M];
}
// 3 -> 4
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i + N][j] = vecArray[i + N][j + M];
}
// 4 -> 1
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i][j] = vecArray[i + N][j];
}
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
vecArray[i][j] = temp[i][j];
}
void six(vector<vector<int>>& vecArray)
{
vector<vector<int>> temp(100, vector<int>(100, 0));
int N = n / 2;
int M = m / 2;
//4번을 3번으로
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i + N][j + M] = vecArray[i + N][j];
}
// 3번을 2번으로
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i][j + M] = vecArray[i + N][j + M];
}
// 2번을 1번으로
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i][j] = vecArray[i][j + M];
}
// 1번을 4번으로
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
temp[i + N][j] = vecArray[i][j];
}
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
vecArray[i][j] = temp[i][j];
}
int main()
{
cin >> n >> m >> r;
vector<vector<int>> vecArray(100, vector<int>(100, 0));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
{
cin >> vecArray[i][j];
}
for (int i = 0; i < r; ++i)
{
int num;
cin >> num;
if (num == 1)
one(vecArray);
else if (num == 2)
two(vecArray);
else if (num == 3)
three(vecArray);
else if (num == 4)
four(vecArray);
else if (num == 5)
five(vecArray);
else if (num == 6)
six(vecArray);
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
cout << vecArray[i][j] << " ";
cout << "\n";
}
return 0;
}
07-2 배열 돌리기 1 ( 16926 )
- 배열과 정수 R이 주어졌을 때, 배열을 R번 회전시킨 결과를 구해보자
#include <iostream>
using namespace std;
int map[300][300];
int n, m, r;
void rotate()
{
// 문제 조건에 min(N, M) mod 2 = 0 라는 힌트가 있다는 것을 명심하자
// 또한 이것은 돌려야 할 사각형 개수이다
int check = min(n, m) / 2;
for (int cnt = 0; cnt < check; cnt++)
{
int n_max = n - 1 - cnt;
int m_max = m - 1 - cnt;
int tmp = map[cnt][cnt];
// 위쪽 변 : 왼 <- 오
for (int i = cnt; i < m_max; i++)
{
map[cnt][i] = map[cnt][i + 1];
}
// 오른쪽 변 : 아래 <- 위
for (int i = cnt; i < n_max; i++)
{
map[i][m_max] = map[i + 1][m_max];
}
// 아래쪽 변 : 왼 -> 오
for (int i = m_max; cnt < i; i--)
{
map[n_max][i] = map[n_max][i - 1];
}
// 왼쪽 변 : 위 -> 아래
for (int i = n_max; cnt < i; i--)
{
map[i][cnt] = map[i - 1][cnt];
}
map[cnt + 1][cnt] = tmp;
}
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(0);
cin >> n >> m >> r;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> map[i][j];
}
}
for (int i = 0; i < r; i++) rotate();
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cout << map[i][j] << ' ';
}
cout << '\n';
}
return 0;
}
07-3 배열 돌리기 2 ( 16927 )
- 배열과 정수 R이 주어졌을 때, 배열을 R번 회전시킨 결과를 구해보자
// https://conkjh032.tistory.com/278 참고
#include<bits/stdc++.h>
using namespace std;
int n, m, r;
int mat[301][301];
void print()
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
cout << mat[i][j] << " ";
cout << endl;
}
}
void solution()
{
// 꼭지점 4개
int y1 = 0;
int x1 = 0;
int y2 = n - 1;
int x2 = 0;
int y3 = n - 1;
int x3 = m - 1;
int y4 = 0;
int x4 = m - 1;
// 가장 바깥 영역부터 안으로 들어가기
while ((y1 < y2) && (x1 < x4))
{
// 영역 내에서 의미있게 회전할 횟수 구하기
// 예를들어 4*4 사이즈의 배열의 0,0이 처음으로
// 돌아오려면 12번 회전 시키면 된다
int move = r % ((y2 - y1) * 2 + (x4 - x1) * 2);
while (move--)
{
// 회전 시키기
int tmp = mat[y1][x1];
// 왼쪽으로
for (int j = x1; j < x4; j++)
mat[y1][j] = mat[y1][j + 1];
// 위로
for (int i = y4; i < y3; i++)
mat[i][x4] = mat[i + 1][x4];
// 오른쪽으로
for (int j = x3; x2 < j; j--)
mat[y3][j] = mat[y3][j - 1];
// 아래로
for (int i = y2; y1 < i; i--)
mat[i][x2] = mat[i - 1][x2];
mat[y1 + 1][x1] = tmp;
}
// 회전이 끝났으면, 영역 옮기기
y1 += 1;
x1 += 1;
y2 -= 1;
x2 += 1;
y3 -= 1;
x3 -= 1;
y4 += 1;
x4 -= 1;
}
print();
}
int main(void)
{
cin >> n >> m >> r;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> mat[i][j];
solution();
}
07-4 주사위 굴리기 ( 14499 )
- 주사위를 놓은 곳의 좌표와 이동시키는 명령이 주어졌을 때, 주사위가 이동했을 때 마다 상단에 쓰여 있는 값을 구하는 프로그램을 작성하시오
https://excited-hyun.tistory.com/215 참고
#include<bits/stdc++.h>
using namespace std;
int mymap[20][20];
int X[5] = { 0, 1, -1, 0, 0 };
int Y[5] = { 0, 0, 0, -1, 1 };
vector<int> dice(6, 0);
int main()
{
int n, m, x, y, k;
scanf("%d %d %d %d %d", &n, &m, &y, &x, &k);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
scanf("%d", &mymap[i][j]);
}
int move;
for (int i = 0; i < k; ++i)
{
scanf("%d", &move);
int newX = x + X[move];
int newY = y + Y[move];
if (newX < 0 || m <= newX || newY < 0 || n <= newY)
continue;
if (move == 1)
dice = { dice[3], dice[1], dice[0], dice[5], dice[4], dice[2] };
else if (move == 2)
dice = { dice[2], dice[1], dice[5], dice[0], dice[4], dice[3] };
else if (move == 3)
dice = { dice[4], dice[0], dice[2], dice[3], dice[5], dice[1] };
else if (move == 4)
dice = { dice[1], dice[5], dice[2], dice[3], dice[0], dice[4] };
if (mymap[newY][newX] == 0)
mymap[newY][newX] = dice[5];
else
{
dice[5] = mymap[newY][newX];
mymap[newY][newX] = 0;
}
cout << dice[0] << endl;
x = newX;
y = newY;
}
return 0;
}
07-5 톱니바퀴 (2) ( 15662 )
- 톱니바퀴 T개의 초기 상태와 톱니바퀴를 회전시킨 방법이 주어졌을 때, 최종 톱니바퀴의 상태를 구하는 프로그램을 작성하시오
// https://intaehwang.tistory.com/108 참고
#include<bits/stdc++.h>
using namespace std;
int gear[1001][8];
int check[1001];
int main()
{
int t;
cin >> t;
for (int i = 1; i <= t; i++)
{
for (int j = 0; j < 8; j++)
scanf("%1d", &gear[i][j]);
}
int k;
cin >> k;
for (int i = 0; i < k; i++)
{
memset(check, 0, sizeof(check));
int x, y;
cin >> x >> y;
check[x] = y;
for (int j = x; j < t; j++)
{
if (gear[j][2] != gear[j+1][6]) check[j+1] = -check[j];
else break;
}
for (int j = x; 1 < j; j--)
{
if (gear[j-1][2] != gear[j][6]) check[j-1] = -check[j];
else break;
}
for (int j = 1; j <= t; j++)
{
if (check[j] == 0) continue;
else if (check[j] == 1)
{
int tmp = gear[j][7];
for(int cur = 7; 0 < cur; --cur) gear[j][cur] = gear[j][cur-1];
gear[j][0] = tmp;
}
else if (check[j] == -1)
{
int tmp = gear[j][0];
for(int cur = 0; cur < 7; ++cur) gear[j][cur] = gear[j][cur+1];
gear[j][7] = tmp;
}
}
}
int ans = 0;
for (int i = 1; i <= t; i++)
if (gear[i][0] == 1) ans += 1;
cout << ans << endl;
}
07-6 로봇 청소기 ( 14503 )
- 로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오
// https://blog.naver.com/PostView.naver?blogId=fbfbf1&logNo=222472445249&categoryNo=34&parentCategoryNo=37&viewDate=¤tPage=1&postListTopCurrentPage=1&from=postView 참고
#include<bits/stdc++.h>
using namespace std;
int board[52][52];
bool check[52][52];
int dy[4] = { -1, 0, 1, 0 };
int dx[4] = { 0, 1, 0, -1 };
int sum = 0;
int main()
{
ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
int N, M, r, c, d;
cin >> N >> M >> r >> c >> d;
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < M; ++j)
{
cin >> board[i][j];
}
}
while (true)
{
if (check[r][c] == false)
{
check[r][c] = true;
sum++;
}
bool ch = false;
for (int i = 0; i < 4; ++i)
{
d = (d + 3) % 4;
int nx = c + dx[d];
int ny = r + dy[d];
if (nx < 0 || ny < 0 || M <= nx || N <= ny) continue;
if (board[ny][nx] == 0 && check[ny][nx] == false)
{
c = nx;
r = ny;
ch = true;
break;
}
}
if (!ch)
{
int back = (d + 2) % 4;
int nx = c + dx[back];
int ny = r + dy[back];
if (nx < 0 || ny < 0 || M <= nx || N <= ny) break;
if (board[ny][nx] == 1) break;
c = nx;
r = ny;
}
}
cout << sum << "\n";
}
07-7 드래곤 커브 ( 15685 )
- 크기가 100×100인 격자 위에 드래곤 커브가 N개 있다. 이때, 크기가 1×1인 정사각형의 네 꼭짓점이 모두 드래곤 커브의 일부인 정사각형의 개수를 구하는 프로그램을 작성하시오
// https://velog.io/@sj-lee33/%EB%B0%B1%EC%A4%80-15685-%EB%93%9C%EB%9E%98%EA%B3%A4-%EC%BB%A4%EB%B8%8C-c-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%92%80%EC%9D%B4 참고
#include<bits/stdc++.h>
using namespace std;
#define MAX 101
int N;
int x, y, d, g, cnt;
int mymap[MAX][MAX];
int dx[4] = { 1, 0, -1, 0 };
int dy[4] = { 0, -1, 0, 1 };
vector<int> direction;
void Make_Dragon_Curve()
{
int size = direction.size();
for (int i = size - 1; 0 <= i; i--)
{
int temp = (direction.at(i) + 1) % 4;
x += dx[temp];
y += dy[temp];
mymap[y][x] = 1;
direction.push_back(temp);
}
}
void Count_Square()
{
for (int i = 0; i < MAX; i++)
{
for (int j = 0; j < MAX; j++)
{
if (mymap[i][j] == 1 && mymap[i][j + 1] == 1 && mymap[i + 1][j + 1] && mymap[i + 1][j] == 1)
cnt++;
}
}
}
void Solution()
{
cin >> N;
while (N--)
{
direction.clear();
cin >> x >> y >> d >> g;
// initialize
mymap[y][x] = 1;
// generation 0
x += dx[d];
y += dy[d];
mymap[y][x] = 1;
direction.push_back(d);
// next 'g' generations
while (g--)
{
Make_Dragon_Curve();
}
}
Count_Square();
cout << cnt << endl;
}
int main()
{
Solution();
}
#include<bits/stdc++.h>
using namespace std;
const int MAX = 100 + 1;
bool visited[MAX][MAX];
vector<pair<int, int>> moveDir = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} };
int main(void)
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int N;
cin >> N;
for (int i = 0; i < N; i++)
{
int y, x, d, g;
cin >> x >> y >> d >> g;
vector<int> curve;
curve.push_back(d);
for (int j = 0; j < g; j++)
{
vector<int> temp = curve;
for (int k = temp.size() - 1; 0 <= k; k--)
curve.push_back((temp[k] + 1) % 4);
}
visited[y][x] = true;
for (int j = 0; j < curve.size(); j++)
{
x += moveDir[curve[j]].first;
y += moveDir[curve[j]].second;
if (0 <= x && x < MAX && 0 <= y && y < MAX)
visited[y][x] = true;
}
}
int result = 0;
for (int j = 0; j < MAX - 1; j++)
for (int k = 0; k < MAX - 1; k++)
if (visited[j][k] && visited[j][k + 1] && visited[j + 1][k] && visited[j + 1][k + 1])
result++;
cout << result << "\n";
return 0;
}
07-8 LCD Test ( 2290 )
- 지민이의 친한 친구인 지환이는 지민이의 새로운 모니터를 위해 테스트 할 수 있는 프로그램을 만들기로 하였다
// https://luvery93.github.io/articles/2018-11/boj-2290 참고
#include<bits/stdc++.h>
using namespace std;
int view[11][5][3] =
{
{ {0,1,0}, {1,0,1}, {0,0,0}, {1,0,1}, {0,1,0} },
{ {0,0,0}, {0,0,1}, {0,0,0}, {0,0,1}, {0,0,0} },
{ {0,1,0}, {0,0,1}, {0,1,0}, {1,0,0}, {0,1,0} },
{ {0,1,0}, {0,0,1}, {0,1,0}, {0,0,1}, {0,1,0} },
{ {0,0,0}, {1,0,1}, {0,1,0}, {0,0,1}, {0,0,0} },
{ {0,1,0}, {1,0,0}, {0,1,0}, {0,0,1}, {0,1,0} },
{ {0,1,0}, {1,0,0}, {0,1,0}, {1,0,1}, {0,1,0} },
{ {0,1,0}, {0,0,1}, {0,0,0}, {0,0,1}, {0,0,0} },
{ {0,1,0}, {1,0,1}, {0,1,0}, {1,0,1}, {0,1,0} },
{ {0,1,0}, {1,0,1}, {0,1,0}, {0,0,1}, {0,1,0} },
};
int main()
{
ios::sync_with_stdio(false);
int s;
string digit;
cin >> s >> digit;
for (int r = 0; r < 5; r++)
{
if (r % 2 == 0)
{
for (int i = 0; i < digit.size(); i++)
{
int d = digit[i] - '0';
cout << ' ';
for (int j = 0; j < s; j++)
{
cout << (view[d][r][1] == 1 ? '-' : ' ');
}
cout << ' ';
cout << (i == digit.size() - 1 ? '\n' : ' ');
}
}
else
{
for (int k = 0; k < s; k++)
{
for (int i = 0; i < digit.size(); i++)
{
int d = digit[i] - '0';
cout << (view[d][r][0] == 1 ? '|' : ' ');
for (int j = 0; j < s; j++)
{
cout << ' ';
}
cout << (view[d][r][2] == 1 ? '|' : ' ');
cout << ' ';
}
cout << '\n';
}
}
}
return 0;
}
07-9 겉넓이 구하기 ( 16931 )
- 이 도형의 겉넓이를 구하는 프로그램을 작성하시오
#include<bits/stdc++.h>
using namespace std;
int n, m, board[102][102];
int dx[4] = { 1, -1, 0, 0 };
int dy[4] = { 0, 0, 1, -1 };
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> board[i][j];
}
}
int res = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
for (int d = 0; d < 4; d++)
{
int ty = i + dy[d];
int tx = j + dx[d];
int gap = board[i][j] - board[ty][tx];
if (gap > 0)
{
res += gap;
}
}
}
}
res += 2 * n * m;
cout << res << '\n';
return 0;
}
07-10 배열 복원하기 ( 16967 )
- 배열 B와 정수 X, Y가 주어졌을 때, 배열 A를 구해보자
#include<bits/stdc++.h>
using namespace std;
int H, W, X, Y;
int B[601][601];
void input_B()
{
for (int i = 0; i < H + Y; i++)
{
for (int j = 0; j < W + X; j++)
{
cin >> B[i][j];
}
}
}
void recover_A()
{
for (int i = Y; i < H; i++)
{
for (int j = X; j < W; j++)
{
B[i][j] = B[i][j] - B[i - Y][j - X];
}
}
}
void print_A()
{
for (int i = 0; i < H; i++)
{
for (int j = 0; j < W; j++)
{
cout << B[i][j] << " ";
}
cout << "\n";
}
}
int main()
{
cin >> H >> W >> Y >> X;
input_B();
recover_A();
print_A();
return 0;
}
07-11 컨베이어 벨트 위의 로봇 ( 20055 )
- 몇 번째 단계가 진행 중일때 종료되었는지 출력한다
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int N, K;
cin >> N >> K;
vector<int> A(2 * N);
vector<bool> occupied(2 * N, false);
for (auto& item : A)
cin >> item;
int counter = 0;
while (true)
{
++counter;
// 1.
rotate(occupied.rbegin(), occupied.rbegin() + 1, occupied.rend());
rotate(A.rbegin(), A.rbegin() + 1, A.rend());
occupied[N - 1] = false;
// 2.
for (int i = N - 1; 0 < i; --i)
{
if (occupied[i-1] && A[i] && !occupied[i])
{
swap(occupied[i-1], occupied[i]);
--A[i];
}
}
occupied[N - 1] = false;
// 3.
if (A[0])
{
occupied[0] = true;
--A[0];
}
// 4.
if (K <= count_if(A.begin(), A.end(), [](int item) { return item == 0; }))
{
break;
}
}
cout << counter;
return 0;
}
Chapter 08 이분 탐색
08-1 기타 레슨 ( 2343 )
- 가능한 블루레이의 크기 중 최소를 구하는 프로그램을 작성하시오
08-2 공유기 설치 (2110)
- 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오
08-3 색종이와 가위 ( 20444 )
- 궁금하지만 화가 나서 코딩에 집중할 수 없는 준성이 대신 코드를 작성해주도록 하자
08-4 징검다리 건너기 (large) ( 22871 )
- 가장 왼쪽 돌에서 출발하여 가장 오른쪽에 있는 돌로 건너갈 수 있는 모든 경우 중 K의 최솟값을 구해보자
08-5 휴게소 세우기 ( 1477 )
- 다솜이는 지금 휴게소를 M개 더 세우려고 한다
08-6 나무 자르기 ( 2805 )
- 이때, 적어도 M미터의 나무를 집에 가져가기 위해서 절단기에 설정할 수 있는 높이의 최댓값을 구하는 프로그램을 작성하시오
08-7 랜선 자르기 ( 1654 )
- 이때 만들 수 있는 최대 랜선의 길이를 구하는 프로그램을 작성하시오
08-8 암벽 등반 ( 2412 )
- 현재 당신이 있는 위치는 (0, 0)이다. 이 위치에서 시작하여 이동 회수를 최소로 하면서 정상에 오르려고 한다
08-9 과자 나눠주기 ( 6236 )
- 현우가 필요한 최소 금액 K를 계산하는 프로그램을 작성하시오
08-10 드래곤 앤 던전 ( 16434 )
- 용사는 수련을 하면 최대 생명력 MaxHP를 늘릴 수 있는데 얼마나 수련해야 할지 고민입니다
댓글남기기