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 107 108 | #define _DE321BUG #include <bits/stdc++.h> using namespace std; #define endl "\n" #define fi first #define se second #define all(x) (x).begin(),(x).end() typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; typedef vector<int> vi; typedef vector<pii> vii; const long double pi = acos(-1.0); const int INF = 1987654321; const ll LLINF = 4e18; const double eps = 1e-9; template<class T>bool chmax(T& a, const T& b) { if (a < b) { a = b; return 1; } return 0; } template<class T>bool chmin(T& a, const T& b) { if (b < a) { a = b; return 1; } return 0; } // int parent[10002][1002]; // kid/vertice int find(int kid, int n){ if(parent[kid][n] == -1) return n; return parent[kid][n] = find(kid, parent[kid][n]); } void merge(int kid, int u, int v){ u = find(kid, u); v = find(kid, v); if(u == v) return; parent[kid][v] = u; } struct Edge{ int idx, u, v, weight; // bool operator<(const Edge &other) const{ // return weight < other.weight; // } bool operator<(const Edge &other) const{ return weight > other.weight; } }; vector<Edge> edges; int main(){ #ifdef _DEBUG freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); #endif ios::sync_with_stdio(false); cin.tie(NULL); memset(parent, -1, sizeof(parent)); int N, M, K; cin >> N >> M >> K; // if(K > 10){ // return 0; // } for(int i = 1; i <= M; i++){ int a, b, c; cin >> a >> b >> c; edges.push_back({i, a, b, c}); } sort(edges.begin(), edges.end()); // for(auto v : edges){ // cout << v.idx << " " << v.u << " " << v.v << " " << v.weight << endl; // } int ans[300004]; memset(ans, 0, sizeof(ans)); for(auto edge : edges){ // for(int i = 1; i <= K; i++){ // if(find(i, edge.u) == find(i, edge.v)) continue; // merge(i, find(i, edge.u), find(i, edge.v)); // ans[edge.idx] = i; // break; // } bool flag = false; int lo = 0; int hi = K; while(lo + 1 < hi){ int mid = (lo + hi)/2; if(find(mid, edge.u) != find(mid, edge.v)){ hi = mid; flag = true; } else{ lo = mid; } } // cout << edge.idx << " " << hi << " " << flag << endl; if(find(hi, edge.u) != find(hi, edge.v)){ merge(hi, find(hi, edge.u), find(hi, edge.v)); ans[edge.idx] = hi; } else{ ans[edge.idx] = 0; } // if(flag) ans[edge.idx] = K-hi; // if(flag) ans[edge.idx] = hi; // else ans[edge.idx] = 0; } for(int i = 1; i <= M; i++) cout << ans[i] << endl; return 0; } | cs |
https://www.acmicpc.net/problem/17726
문제 설명:
가중치가 C인 양방향 A<->B 그래프. K명이 있을때 1번부터 K번까지 가중치의 합이 가장 크도록 간선들을 선택함. 이 때 선택한 간선들이 사이클을 이루면 안 됨. 1 ~ K번의 사람이 각각 최대로 가져간 간선의 가중치의 합은?
서브태스크 1 :
10명밖에 없기 때문에 모든 간선에 대해 1 ~ 10번까지 크루스칼 알고리즘을 변형해서 최대한 앞 번호한테 주면 됨.
서브태스크 2 :
10000명이나 존재하기 때문에 서브태스크 1의 과정을 O(K) -> O(logK)로 줄여야 됨. 이분탐색을 이용해서 주면 되는데, 임의의 Q가 간선을 가져갈 수 없으면 1 ~ Q-1 모두 가져갈 수 없다는게 그리디하게 증명이 되기 때문에 가능함.
댓글 0