※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 27730번 문제인 견우와 직녀이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/27730

 

오작교를 이을 \(E\)의 정점 번호를 \(e\), \(W\)의 정점 번호를 \(w\)라 하자. 이 때 \(E\)와 \(W\)의 정점 쌍 사이의 거리의 총합을 (1) \(E\)의 각 정점으로부터 \(e\)로 이동을 \(W\)의 정점의 개수만큼, (2) \(e\)에서 \(w\)로 이동을 \(E\)와 \(W\)의 정점 쌍의 개수만큼, , (3) \(w\)로부터 \(W\)의 각 정점으로 이동을 \(E\)의 정점의 개수만큼 하는 것으로 나누어 생각해보자. 이 중 \(E\)와 \(W\)의 크기는 주어지는 값으로 고정되므로, 주어진 트리에서 모든 정점까지의 거리의 총합이 가장 작은 정점을 찾을 수 있다면 문제를 해결할 수 있게 된다.

 

트리에서 모든 정점까지의 거리의 총합이 가장 작은 정점을 찾아 문제를 해결하자. 이는 DP를 이용해 어렵지 않게 구할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;

ll N;
vector<pair<int, ll>> G[100001];
ll streecnt[100001];
ll dp[100001];
ll dp2[100001];
void func(int cur, int par) {
    ll &val = dp[cur] = 0;
    streecnt[cur] = 1;
    for (auto &p:G[cur]) {
        if (p.first == par) continue;
        func(p.first, cur);
        val += streecnt[p.first] * p.second + dp[p.first];
        streecnt[cur] += streecnt[p.first];
    }
}

void func2(int cur, int par, ll pval) {
    if (!par) dp2[cur] = dp[cur];
    else {
        dp2[cur] = dp2[par] - streecnt[cur] * pval + (N - streecnt[cur]) * pval;
    }
    for (auto &p:G[cur]) {
        if (p.first == par) continue;
        func2(p.first, cur, p.second);
    }
    
}
ll anode1, aval1, sz1, anode2, aval2, sz2;

void solve(ll &an, ll &av, ll &z) {
    cin >> N; z = N;
    for (int i = 1; i <= N; i++) G[i].clear();
    memset(streecnt, 0, sizeof(streecnt));
    for (int i = 1; i < N; i++) {
        int x, y, w; cin >> x >> y >> w;
        G[x].emplace_back(make_pair(y, w));
        G[y].emplace_back(make_pair(x, w));
    }

    func(1, 0);
    func2(1, 0, 0);
    av = 1000000000000000007LL;
    for (int i = 1; i <= N; i++) {
        if (dp2[i] < av) av = dp2[i], an = i;
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    solve(anode1, aval1, sz1);
    solve(anode2, aval2, sz2);
    cout << anode1 << ' ' << anode2 << '\n';
    cout << aval1 * sz2 + aval2 * sz1 + sz1 * sz2;

}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 24649 // C++] Letters Q and F  (0) 2024.07.18
[BOJ 11541 // C++] At most twice  (1) 2024.07.17
[BOJ 30512 // C++] 조용히 완전히 영원히  (0) 2024.07.15
[BOJ 13473 // C++] Anniversary Cake  (1) 2024.07.14
[BOJ 11268 // C++] Bell Ringing  (0) 2024.07.13

+ Recent posts