[Baekjoon,1774]우주신과의 교감

1 분 소요

해결

이 문제는 algospot 사이트의 LAN이라는 문제와 해결방법 이 유사하다.
크루스칼의 알고리즘과 프림의 알고리즘 중 나는 프림의 알고리즘으로 해결했다.

프림의 알고리즘은 전체 그래프에서 어느 정점을 시작으로 연결된 간선 중 가장 가중치가 작은 간선을 하나씩 선택해 나아가 최소 스패닝 트리를 만드는 알고리즘이다. 이 문제에서 이미 연결되어 있는 정점들의 간선의 가중치를 0으로 설정하여 해결했다. 이러면 따로 구하지 않아도 되어 편하다.

연결되지 않은 정점은 초기에 INF로 설정하고 갱신해야 하는 시점에 두 점사이의 거리를 구해 간선의 가중치를 형성했다. 선택된 간선들의 가중치의 합을 구하면 결과가 된다.

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

const int MAX_V=1001;
const double INF=numeric_limits<double>::max( );

int V,E;
int X[MAX_V], Y[MAX_V];
double adj[MAX_V][MAX_V];

double calcDist(int u, int v)
{
    return adj[u][v]=adj[v][u]=sqrt(pow(X[u]-X[v],2)+pow(Y[u]-Y[v],2));
}

double prim()
{
    vector<double> minDist(V,INF);
    vector<bool> added(V,false);
    
    double ret=0.0;
    minDist[0]=0;
    for(int it=0;it<V;++it)
    {
        int u=-1;
        for(int v=0;v<V;++v)
            if(!added[v] && (u==-1 || minDist[u]>minDist[v]))
            {
                u=v;
                if(minDist[u]==0)
                    break;
            }
        
        added[u]=true;
        ret+=minDist[u];
        for(int v=0;v<V;++v)
        {
            if(added[v])
                continue;
            double dist=(adj[u][v]==INF) ? calcDist(u,v) : adj[u][v];
            minDist[v]=min(minDist[v],dist);
        }
    }
    return ret;
}

int main()
{
    cin>>V>>E;
    
    for(int i=0;i<V;++i)
        cin>>X[i]>>Y[i];
    
    for(int i=0;i<V;++i)
        for(int j=0;j<V;++j)
            adj[i][j]=INF;
    
    for(int i=0;i<E;++i)
    {
        int a,b;
        cin>>a>>b;
        --a; --b;
        adj[a][b]=adj[b][a]=0;
    }
    cout<<fixed;
    cout.precision(2);
    cout<<prim()<<endl;

    return 0;
}

회고

초기에 minDist를 minDistSqr 형태로 저장했는데 이는 위치가 1,000,000이 될 수 있기 때문에 int형 자료형은 초과될 수 있다. 이 때문에 한참 디버깅했다. 결국 double로 선언하여 sqrt()를 적용한 상태로 저장하니 쉽게 해결되었다.

댓글남기기