2. 이분탐색에서의 조건은 휴게소 간격들 사이 해당 거리(mid) 만큼 지정했을 때, 배치 가능한 갯수
문제풀이
주석을 자세하게 적어 놓아기 때문에 생략
정답 코드입니다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n, m, l;
vector <int> vec;
bool cmp(int& a, int& b) { // 없어도 되지만 간만에 짜보고 싶었어요ㅋㅋ
if (a < b)
return true;
return false;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m >> l;
int temp;
vec.push_back(0), vec.push_back(l); //시작점과 끝점 추가 + 이미 휴게소가 있는 곳에 휴게소를 또 세울 수 없고, 고속도로의 끝에도 휴게소를 세울 수 없다. 라는 조건 때문에
for (int i = 0; i < n; i++) {
cin >> temp;
vec.push_back(temp);
}
sort(vec.begin(), vec.end(), cmp);
int low = 0, high = l;
int mid, result = 0;
while (low <= high) {
mid = (low + high) / 2;
int val = 0; // 휴게소 사이에 배치 될 수있는 휴게소의 갯수
for (int i = 1; i < vec.size(); i++) {
int dist = vec[i] - vec[i - 1]; // 휴게소 a와 b 사이에 간격
val += (dist / mid); // 휴게소 간격 / 현재 길이
if (dist%mid == 0) //휴게소가 이미 있는 위치라면
val--; // 갯수를 하나 감소 시켜주어야지.
}
if (val > m) // 배치할 수 있는 휴게소가 m개 보다 많으면
low = mid + 1; // 길이를 늘려주어 m개가 배치 되게끔 만들어주고
else {// 배치될 휴게소가 m개보다 작거나 같을 때
high = mid - 1;// 길이(mid)가 더 작아질 수 있을지 확인해야지
result = mid; //결과값을 갱신해주기
}
}
cout << result << endl;
return 0;
}
4일 동안 반례를 못찾고 시름시름 앓고 있었는데, bamgoesn 님께서 반례를 찾아주셨다. ㅠㅠ
다시 한번 감사드립니다. ㅠㅠ
구현 + bfs 문제입니다.
어떻게 보면 시뮬레이션이기도 하고, bfs 심화같기도 한 문제.
접근방식
1. 우선 빈칸들의 좌표별로 이동가능한 값들을 저장해야한다.
이때, 구획별로 번호를 매겨주어서 벽을 허물었을 때, 중복으로 구획을 세지 않도록 한다.
2. 벽을 하나씩 부서보면서 해당하는 좌표의 값을 도출한다.
문제풀이
1.bfs를 통해서 빈 좌표별로 이동가능한 최대한 값을 도출한다.
2. 다시 한번 bfs를 통해 이번엔 구획에 해당하는 모든 값들에 이동가능한 값과 구획번호를 저장
3. 벽 좌표를 vector에 저장하고 하나씩 부서보면서 결과를 도출
이때, 구획번호가 중복이 되지 않겠끔 vector에 구획번호를 저장하면서 4방향을 모두 확인
정답코드입니다.
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
int n, m;
int arr[1001][1001] = { 0, };
vector <pair<int, int>> block;
int result[1001][1001] = { 0, };
int visited[1001][1001][2] = { 0, }; // 첨에는 이동 가능한 개수를 저장할거고, 두번째에는 고유 영역 값을 저장할 예정
int vis_cnt = 1; // 구획의 첫 번호는 1부터
bool temp_v[1001][1001] = { 0, }; //난 bfs로 구현할거야, 얘는 탐색을 위해 사용할 배열
int y_ar[4] = { -1,0,1,0 };
int x_ar[4] = { 0,1,0,-1 };
void bfs(int ty, int tx) {
// 1. temp_v를 사용해서 이동 가능한 개수 파악하기
int maxed = 1;
temp_v[ty][tx] = 1;
queue <pair<int, int>> que;
que.push(make_pair(ty, tx));
while (!que.empty()) {
int cy = que.front().first;
int cx = que.front().second;
que.pop();
for (int i = 0; i < 4; i++) {
int ny = cy + y_ar[i];
int nx = cx + x_ar[i];
if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] != 0)
continue;
if (temp_v[ny][nx] != 0)
continue;
temp_v[ny][nx] = 1;
que.push(make_pair(ny, nx));
maxed++;
}
}
//cout << maxed << endl;
// 2. visited에 이동가능한 개수와 자신의 구획번호를 입력하기
visited[ty][tx][0] = maxed;
visited[ty][tx][1] = vis_cnt;
que.push(make_pair(ty, tx));
while (!que.empty()) {
int cy = que.front().first;
int cx = que.front().second;
que.pop();
for (int i = 0; i < 4; i++) {
int ny = cy + y_ar[i];
int nx = cx + x_ar[i];
if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] != 0)
continue;
if (visited[ny][nx][0] != 0)
continue;
visited[ny][nx][0] = maxed;
visited[ny][nx][1] = vis_cnt;
que.push(make_pair(ny, nx));
}
}
vis_cnt++; //인덱스를 하나 올려준다.
}
int main() {
ios_base::sync_with_stdio(0);
cin >> n >> m;
for (int i = 0; i < n; i++) {
string temp;
cin >> temp;
for (int j = 0; j < m; j++) {
arr[i][j] = temp[j] - '0';
if (arr[i][j] == 1)
block.push_back(make_pair(i, j));
}
}
//cout << block.size() << endl;
//1. 영역별로 마킹하기!
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (temp_v[i][j] == 0 && arr[i][j] == 0) { // 벽이 아니고, 방문한 적이 없다면 탐색해야해!
bfs(i, j);
}
/*
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cout << visited[i][j][1] << ' ';
}
cout << endl;
}
*/
//2. 벽을 하나씩 부수면서 이동가능한 결과값을 도출하는 과정
vector <int> index; // index 값들을 임시 저장할 친구
for (int i = 0; i < block.size(); i++) {
index.clear();
int val = 1; //자신을 포함해야 하니 1 부터 시작한다.
int y = block[i].first;
int x = block[i].second;
for (int j = 0; j < 4; j++) {
bool flag2 = true;
int ny = y + y_ar[j];
int nx = x + x_ar[j];
if (ny < 0 || ny >= n || nx < 0 || nx >= m || arr[ny][nx] == 1)
continue;
for (int i = 0; i < index.size(); i++)
if (visited[ny][nx][1] == index[i]) {
flag2 = false;
break;
}
if (flag2 == true) {
val += visited[ny][nx][0];
index.push_back(visited[ny][nx][1]);
}
}
result[y][x] = val % 10;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
printf("%d", result[i][j]);
printf("\n");
}
}
B(2,2)와 C(2,3)는 2,2 -> 1,2 -> 1,3 -> 2,3 경로로 움직여서 길을 포함하지 않더라도 만날 수 있습니다.
하지만 A,B와 A,C는 길을 포함하지 않고 만날 수 가 없습니다.
그래서 총 2쌍이라는 겁니다.
접근방식
1. 일반적인 bfs로 구현해보자
문제풀이
1. 길을 마킹할 배열 arr[101][101][4] 를 생성 북,동,남,서 순으로 이동이 불가한 위치를 표시할 용도
2. bfs를 통해 소 기준으로 이동이 불가한 소들을 도출
3. bfs를 반복해줄때, 이전 소들은 확인할 필요없이 자신보다 인덱스가 높은 소들만 확인해주면서 넘어가야 중복이 안생김
코드를 직접 확인하는게 더 빠를 것 같음
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
int n, k, R;
int arr[101][101][4] = { 0, }; // 4방향에 대해서 길이 있을 수 있으니.. 북 동 남 서 순으로 저장할거
bool visited[101][101];
int y_ar[4] = { -1,0,1,0 };
int x_ar[4] = { 0,1,0,-1 };
vector <pair<int, int>> cow;
int result = 0;
void bfs(int sy, int sx) {
queue <pair<int, int >> que;
que.push(make_pair(sy, sx));
visited[sy][sx] = 1;
while (!que.empty()) {
int cy = que.front().first;
int cx = que.front().second;
que.pop();
for (int i = 0; i < 4; i++) {
if (arr[cy][cx][i] == 1) continue; //도로가 있는건 탐색 안해줄거야
int ny = cy + y_ar[i];
int nx = cx + x_ar[i];
if (ny <1 || ny > n || nx < 1 || nx > n || visited[ny][nx] == 1)
continue;
que.push(make_pair(ny, nx));
visited[ny][nx] = 1;
}
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k >> R;
int r, c, rr, cc;
for (int i = 0; i < R; i++) {
cin >> r >> c >> rr >> cc;
for (int j = 0; j < 4; j++) {
int nr = r + y_ar[j];
int nc = c + x_ar[j];
if (nr == rr && nc == cc) {
arr[r][c][j] = 1; // 다리 생성
arr[rr][cc][(j + 2)%4] = 1;
}
}
}
for (int i = 0; i < k; i++) {
cin >> r >> c;
cow.push_back(make_pair(r, c));
}
for (int i = 0; i < k; i++) {
memset(visited, 0, sizeof(visited));
bfs(cow[i].first, cow[i].second);
for (int j = i + 1; j < k; j++) {
if (visited[cow[j].first][cow[j].second] == 0)
result++;
}
}
cout << result << endl;
return 0;
}
O(V^3) 만큼 반복하면서 모든 노드의 최단거리를 도출하고 결과값을 도출하는 문제입니다.
아래는 정답 코드입니다.
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
/*
주의점
1. 중복경로에 대한 예외처리
2. long long
*/
int v, e;
long long arr[401][401];
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> v >> e;
for (int i = 1; i <= v; i++)
for (int j = 1; j <= v; j++) {
if (i == j) arr[i][j] = 0;
else arr[i][j] = 2000000000;
}
int a, b, c;
for (int i = 0; i < e; i++) {
cin >> a >> b >> c;
if (arr[a][b] > c) //중복경로
arr[a][b] = c;
}
//플로이드 와샬
for (int k = 1; k <= v; k++)
for (int i = 1; i <= v; i++)
for (int j = 1; j <= v; j++)
arr[i][j] = min(arr[i][j], arr[k][j] + arr[i][k]);
long long result = 2000000000;
for (int i = 1; i <= v; i++)
for (int j = 1; j <= v; j++) {
if (i == j) continue;
result = min(result, arr[i][j] + arr[j][i]);
}
if (result == 2000000000)
cout << -1 << endl;
else
cout << result << endl;
return 0;
}