순환 구조에서의 최단 거리 및 기하 알고리즘 응용

순환 링에서 로봇의 이동 시간 계산 로봇이 원형 경로 상의 점들 사이를 이동하며, 서로 만날 경우 방향을 반전한다. 주어진 조건 하에서 모든 점을 방문하는 데 걸리는 최소 시간을 구하는 문제이다. 이는 각 위치에서 가장 가까운 로봇까지의 이동 시간을 계산하는 것으로 복잡도를 줄일 수 있다.

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

int n, m;
vector<int> pos;
vector<int> dir;
bool visited[2000010];

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int p; char d;
        cin >> p >> d;
        pos.push_back(p);
        dir.push_back(d == 'R' ? 1 : -1);
    }

    int time = 0;
    int count = 0;
    for (int i = 0; i < n; ++i) {
        if (!visited[i]) {
            visited[i] = true;
            count++;
        }
    }

    while (count < n) {
        time++;
        vector<int> new_pos;
        for (int i = 0; i < m; ++i) {
            int next = pos[i] + dir[i];
            if (next >= n) next -= n;
            if (next < 0) next += n;
            new_pos.push_back(next);
        }
        for (int p : new_pos) {
            if (!visited[p]) {
                visited[p] = true;
                count++;
            }
        }
    }

    cout << time << endl;
    return 0;
}

반지름 기준의 최적 접근: 왼쪽 오른쪽 로봇의 최단 도착 시간 비교 각 위치에 대해 왼쪽에서 오는 오른쪽 이동 로봇과 오른쪽에서 오는 왼쪽 이동 로봇 중 더 빠르게 도착하는 시간을 계산하여 전체 최대값을 찾는다.

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

typedef long long ll;
const int MAXN = 2000005;
const int INF = 1e9;

int n, m;
vector<int> left_robot(MAXN, 0);   // 오른쪽에서 오는 로봇의 최종 위치
vector<int> right_robot(MAXN, 0);  // 왼쪽에서 오는 로봇의 최종 위치

// 왼쪽에 있는 R 로봇이 현재 위치에 도달하는 최소 시간
int get_right_time(int r_pos, int target) {
    if (r_pos == 0) return INF;
    if (r_pos <= target) return target - r_pos;
    return n - (r_pos - target);
}

// 오른쪽에 있는 L 로봇이 현재 위치에 도달하는 최소 시간
int get_left_time(int l_pos, int target) {
    if (l_pos == 0) return INF;
    if (l_pos >= target) return l_pos - target;
    return n - (target - l_pos);
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int x; char op;
        cin >> x >> op;
        if (op == 'R') left_robot[x] = x;
        else right_robot[x] = x;
    }

    // 왼쪽에서 오는 로봇의 전파
    for (int i = 1; i <= n; ++i)
        left_robot[i] = max(left_robot[i], left_robot[i-1]);
    for (int i = 1; i <= n; ++i)
        if (left_robot[i] == 0) left_robot[i] = left_robot[n];

    // 오른쪽에서 오는 로봇의 전파
    for (int i = n; i >= 1; --i)
        right_robot[i] = right_robot[i+1] ? right_robot[i+1] : right_robot[i];
    for (int i = n; i >= 1; --i)
        if (right_robot[i] == 0) right_robot[i] = right_robot[1];

    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int t = min(get_right_time(left_robot[i], i), get_left_time(right_robot[i], i));
        ans = max(ans, t);
    }

    cout << ans << endl;
    return 0;
}

두 점 간의 최단 거리: 움직이는 점과 정지한 점 사이의 거리 두 차원 평면에서 한 점이 일정한 방향 벡터로 연속적으로 이동할 때, 다른 고정된 점과의 최단 거리를 구하는 문제. 이는 선분 위의 점에서의 수직 거리와 끝점 거리 중 작은 값으로 결정된다.

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

struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
};

double distance(const Point& a, const Point& b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double triangle_area(const Point& A, const Point& B, const Point& C) {
    double a = distance(B, C), b = distance(A, C), c = distance(A, B);
    double p = (a + b + c) / 2.0;
    return sqrt(p * (p - a) * (p - b) * (p - c));
}

bool is_obtuse(const Point& A, const Point& B, const Point& C) {
    double a = distance(B, C), b = distance(A, C), c = distance(A, B);
    return b * b > a * a + c * c;
}

double min_distance_to_segment(const Point& A, const Point& B, const Point& C) {
    double d1 = distance(A, C), d2 = distance(B, C);
    if (is_obtuse(C, A, B) || is_obtuse(C, B, A))
        return min(d1, d2);
    double area = triangle_area(A, B, C);
    return 2.0 * area / distance(A, B);
}

int main() {
    int n;
    double x0, y0, x, y;
    cin >> n >> x0 >> y0 >> x >> y;

    Point target(x, y);
    Point current(x0, y0);
    double min_dist = 1e16;

    for (int i = 0; i < n; ++i) {
        double dx, dy;
        cin >> dx >> dy;
        Point next(current.x + dx, current.y + dy);
        min_dist = min(min_dist, min_distance_to_segment(current, next, target));
        current = next;
    }

    printf("%.8f\n", min_dist);
    return 0;
}

선분 교차 여부 판단: 순환 배열 기반 조합 분석 26개의 알파벳으로 구성된 순환 배열에서, 두 선분이 교차하는 쌍의 수를 세는 문제. 각 알파벳의 시작/끝 지점을 저장하고, 한 선분의 내부에 다른 선분의 단 하나의 점이 존재하면 교차함.

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

vector<int> positions[26];

int main() {
    string s;
    cin >> s;

    for (int i = 0; i < s.size(); ++i)
        positions[s[i] - 'A'].push_back(i);

    int result = 0;
    for (int i = 0; i < 26; ++i) {
        for (int j = i + 1; j < 26; ++j) {
            int cnt = 0;
            for (int pos : positions[j])
                if (positions[i][0] < pos && pos < positions[i][1])
                    cnt++;
            if (cnt == 1) result++;
        }
    }

    cout << result << endl;
    return 0;
}

원형 공간에서의 최소 이동 비용: 모든 문을 열 때의 최적 선택 n개의 우물이 원형으로 배치되어 있으며, 한 개의 문에서 시작하여 모든 소가 이동하는 총 거리를 최소화하는 문제. 각 시작 위치에 대해 전체 이동 거리를 계산하고, 최소값을 반환한다.

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

int main() {
    int n;
    cin >> n;
    vector<int> cows(n);
    for (int i = 0; i < n; ++i)
        cin >> cows[i];

    int min_cost = INT_MAX;
    for (int start = 0; start < n; ++start) {
        int cost = 0;
        for (int j = 1; j < n; ++j)
            cost += j * cows[(start + j) % n];
        min_cost = min(min_cost, cost);
    }

    cout << min_cost << endl;
    return 0;
}

축소된 사각형 최소 면적: 점 제거 후 최소 포함 영역 주어진 점들 중 하나를 제거했을 때, 남은 점들을 포함하는 최소 사각형의 면적을 구하는 문제. 해당 점이 최대/최소 좌표에 있지 않으면 무시 가능하다.

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

int main() {
    int n;
    cin >> n;
    vector<int> x(n), y(n);
    for (int i = 0; i < n; ++i)
        cin >> x[i] >> y[i];

    vector<int> xs = x, ys = y;
    sort(xs.begin(), xs.end());
    sort(ys.begin(), ys.end());

    int min_area = INT_MAX;
    for (int i = 0; i < n; ++i) {
        int xmin = (x[i] == xs[0]) ? xs[1] : xs[0];
        int xmax = (x[i] == xs[n-1]) ? xs[n-2] : xs[n-1];
        int ymin = (y[i] == ys[0]) ? ys[1] : ys[0];
        int ymax = (y[i] == ys[n-1]) ? ys[n-2] : ys[n-1];
        min_area = min(min_area, (ymax - ymin) * (xmax - xmin));
    }

    cout << min_area << endl;
    return 0;
}

등록된 상태 전이: 비트마스크 기반 상태 변화 모델링 n개의 전구가 있으며, 각 전구는 이전 전구의 상태에 따라 전환된다. 상태를 비트로 표현하고, 주어진 시간 이후의 상태를 출력하는 문제. 사이클 감지를 통해 반복 계산을 피한다.

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

typedef long long LL;

const int MAX_STATE = 1 << 16;
int state[MAX_STATE];

int update(int s, int n) {
    int res = 0;
    for (int i = 0; i < n; ++i) {
        int prev_bit = (s >> ((i - 1 + n) % n)) & 1;
        int curr_bit = (s >> i) & 1;
        res |= (curr_bit ^ prev_bit) << i;
    }
    return res;
}

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

    int current_state = 0;
    for (int i = 0; i < n; ++i) {
        int bit;
        cin >> bit;
        current_state |= bit << i;
    }

    memset(state, -1, sizeof(state));
    state[current_state] = 0;

    for (int step = 1; step <= m; ++step) {
        current_state = update(current_state, n);
        if (state[current_state] == -1) {
            state[current_state] = step;
        } else {
            int cycle_len = step - state[current_state];
            int remaining = (m - step) % cycle_len;
            while (remaining--) {
                current_state = update(current_state, n);
            }
            break;
        }
    }

    for (int i = 0; i < n; ++i)
        cout << ((current_state >> i) & 1) << "\n";

    return 0;
}

직각 삼각형 최대 면적: 정렬 기반 탐색 주어진 점들 중 세 점이 같은 행/열에 있을 때 직각삼각형을 만들 수 있으며, 그 면적을 계산해 최댓값을 찾는 문제.

#include
#include
using namespace std;

struct Point {
int x, y;
};

int main() {
int n;
cin >> n;
vector points(n);
for (int i = 0; i < n; ++i)
cin >> points[i].x >> points[i].y;

int max_area = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < n; ++k) {
if (i != j && j != k && i != k) {
if (points[i].x == points[j].x && points[i].y == points[k].y) {
int width = abs(points[j].y - points[i].y);
int height = abs(points[k].x - points[i].x);
max_area = max(max_area, width * height);
}
}
}
}
}

cout << max_area << endl;
return 0;
}

태그: 순환 구조 기하 알고리즘 비트마스크 선분 교차 최소 면적

8월 6일 04:00에 게시됨