백준: Class 5 - 2098, 2887

2 분 소요


</br> 클래스 5 계속
</br>

2098: 외판원 순회

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

int dp[17][65536];
int graph[17][17];
int n, endset;

int func(int ii, int kk){
    if( kk == endset ){
        if( graph[ii][0] != 0 ) return graph[ii][0];
        return MAX;
    }

    if( dp[ii][kk] != MAX ) return dp[ii][kk];

    for(int k = 0; k < n; k++){
        if( !(kk & (1 << k)) && graph[ii][k] != 0 ){
            int s = kk | (1 << k);
            dp[ii][kk] = min(dp[ii][kk], func(k, s) + graph[ii][k]);
        }
    }
    return dp[ii][kk];
}

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

    cin >> n;
    endset = (1<<n)-1;

    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            cin >> graph[i][j];
        }
    }
    for(int i = 0; i < n; i++){
        for(int k = 0; k < (1<<n); k++){
            dp[i][k] = MAX;
        }
    }

    cout << func(0, 1) << endl;

}

이제 슬슬 비트로 dp하기(이전 상태 다 저장하기)가 익숙해지는 거 같다
근데 바텀 업으로 하니까 잘 모르겠어서 탑 다운으로 했다.
외판원 순회는 한 곳에서 출발한 경우만 봐도 된다. 만약 1에서 시작한 최적 경로가 1-2-3-4-5-1이라면, 2에서 시작한 최적 경로는 2-3-4-5-1-2일 것이 당연하기 때문이다.

</br>

2887: 행성 터널

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

struct UnionFind{
    vector<int> parent, ran;
    UnionFind(int n) : parent(n), ran(n, 1) {
        for(int i = 0; i < n; i++){
            parent[i] = i;
        }
    }
    int f(int u){
        if( u == parent[u] ) return u;
        return parent[u] = f(parent[u]);
    }
    bool merg(int u, int v){
        u = f(u); v = f(v);
        if( u == v ) return false;
        if( ran[u] > ran[v] ) swap(u, v);
        parent[u] = v;
        ran[v] += ran[u];
        ran[u] = 0;
        return true;
    }
};

// in main()
    for(int i = 0; i < n; i++){
        int a, b, c;
        cin >> a >> b >> c;
        x[i] = make_pair(a, i);
        y[i] = make_pair(b, i);
        z[i] = make_pair(c, i);
    }
    sort(x, x+n);
    sort(y, y+n);
    sort(z, z+n);
    priority_queue<T, vector<T>, greater<>> pq;
    for(int i = 1; i < n; i++){
        pq.push(make_tuple(x[i].first - x[i-1].first, x[i].second, x[i-1].second));
        pq.push(make_tuple(y[i].first - y[i-1].first, y[i].second, y[i-1].second));
        pq.push(make_tuple(z[i].first - z[i-1].first, z[i].second, z[i-1].second));
    }

    UnionFind uf = UnionFind(n);
    int ans = 0;
    while( pq.size() ){
        int w = get<0>(pq.top());
        int a = get<1>(pq.top());
        int b = get<2>(pq.top());
        pq.pop();

        if( uf.merg(a, b) ) ans += w;
    }

    cout << ans << endl;

오랜만에 또 크루스칼 문제다
주의할 점은 행성 수가 10만이라서 메모리와 시간 문제로 엣지를 다 비교할 수는 없다. 따라서 각각 정렬 후에 가까운 애들끼리만 넣어준다.

</br>


오늘은 8월 28일
방학 안에 학교 랭킹 50등 안쪽하고 플래티넘 5 가기 했는데 성공했다
그래도 물렙이니까 열심히 복습도 하고 앞으로도 꾸준히 풀자
</br>

댓글남기기