티스토리 뷰
[Codeforces 1081D] Maximum Distance -1800
문제 설명 :
n개의 vertex와 그 중에서 k개의 special vertex를 가지는 그래프가 주어진다. 문제는 각 special vertex간의 최장거리를 구하면 되는데, 이 문제 내에서 정의하는 '거리'란 edge들의 가중치의 합이 아닌 edge들의 가중치 중에서 가장 큰 값을 거리라고 정의한다. 예를 들어서 1->2로 가는데 가중치가 10, 2->3으로 가는데 가중치가 20이라면 1->3으로 가는 거리는 30이 아닌 20이 되는 것이다.
풀이 :
이 문제는 MST(minimum spanning tree)로 풀면 된다. 즉 edge의 가중치를 오름차순으로 정렬한 뒤, special vertex가 모두 connected될 때까지 계속 연결한다. 그러다가 모두 connected되는 순간 그 때 해당하는 edge의 가중치가 정답이 된다(모든 special vertex에 대하여). 이 문제에서는 '거리'라는 개념을 특별하게 정의하고 있다. 가중치들의 합이 아닌 가중치들 중에서 가장 큰 가중치가 거리가 되므로 내가 거리를 구하기 위해서 필요한 것은 special vertex끼리 모두 connected되게 만드는 edge중에서 가장 가중치가 큰 edge 딱 하나만 알면 되는 것이다. 나머지 edge들은 그보다 작을 것이므로 답에는 아무런 상관이 없다. 노드들을 최소비용으로 connected 되도록 만드는 알고리즘이 바로 MST라고 생각하면 된다.
주의할 점 :
노드들을 merge해나가는 과정에서 언제 special vertex들이 모두 connected 되었는지 판단해야하는 문제가 있다. 그 방법은 집합 안에 special vertex가 몇 개 들어있는지를 따로 저장해놓는 것이다. 그러면 a노드와 b노드를 merge하는 과정에서 (a와 b가 disjoint상태라면) 두 노드의 special vertex의 개수를 더해주면 된다. 더한 개수가 총 special vertex의 개수(=k)와 같아지면 모두 connected 되었다고 판단하면 된다. 이에 대한 구현은 아래 코드의 64~66줄에 나와있고, 이를 저장하는 변수는 good_cnt[]이다.
배운 점 :
MST로 푸는 줄 알면 금방 풀 수 있는 문제인데 그걸 생각해내기가 어려웠다. MST는 특정 노드들을 최소 cost를 사용해서 모두 connected 되도록 만드는데 사용한다. 이 문제가 거기에 해당된다.
코드 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #include<stdio.h> #include<math.h> #include<string.h> #include<iostream> #include<functional> #include<string> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<assert.h> #include<stdlib.h> #include<stack> using namespace std; /*********************Contest Template***********************/ typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<long long,long long> pll; typedef pair<int,int> Cord; struct S{ int a,b; S(){} S(int _a,int _b){ a=_a; b=_b; } const bool operator<(const S &o) const{ return a<o.a; } }; priority_queue<int,vector<int>,greater<int>> mpq; #define SPACE 0 #define NL 1 inline void showAll(vector<int> &v,int NL_or_space){ //0 is space, 1 is NL for(int &here:v){ printf("%d",here); printf("%c",(NL_or_space)?'\n':' '); } } /*********************Contest Template***********************/ const int SIZE= 100009; vector<pii> graph[SIZE]; vector<pair<int,pii>> edge; int p[SIZE],good_cnt[SIZE]={0}; bool pii_cmp(const pair<int,pii> &A,const pair<int,pii> &B){ return A.second.second<B.second.second; } int find(int a){ if(p[a]==-1) return a; return p[a]=find(p[a]); } int merge(int a,int b){ a=find(a),b=find(b); if(a==b) return 0; p[b]=a; good_cnt[a]+=good_cnt[b]; good_cnt[b]=0; return good_cnt[a]; } int main(){ int n,m,k; scanf("%d %d %d",&n,&m,&k); for(int i=1 ; i<=k ; i++){ int inp; scanf("%d",&inp); good_cnt[inp]=1; } for(int i=1 ; i<=m ; i++){ int u,v,c; scanf("%d %d %d",&u,&v,&c); graph[u].push_back({v,c}); graph[v].push_back({u,c}); edge.push_back({u,{v,c}}); } for(int i=1 ; i<=n ; i++) p[i]=-1; sort(edge.begin(),edge.end(),pii_cmp); int ans,cnt=0; for(auto &here:edge){ int cur=here.first,to=here.second.first,cost=here.second.second; if(find(cur)!=find(to)){ int cur_cnt=merge(cur,to); if(cur_cnt==k){ ans=cost; break; } } } for(int i=0 ; i<k ; i++) printf("%d ",ans); return 0; } | cs |
'Problem Solving > Union-Find & MST' 카테고리의 다른 글
[CF 1187C] Vasya And Array (0) | 2019.08.23 |
---|