【BFS】【最小生成树】Petrozavodsk Winter Training Camp 2018 Day 1: Jagiellonian U Contest, Tuesday, January 30, 2018 Problem G. We Need More Managers!

题意:给你n个点,点带权,任意两点之间的边权是它们的点权的异或值中“1”的个数,问你该图的最小生成树。

看似是个完全图,实际上有很多边是废的。类似……卡诺图的思想?从读入的点出发BFS,每次只到改变它的任意一位所能到达的点(不论是否读入)。

记录每个点是从哪个读入点BFS过来的,当第二次访问某个点的时候,就将它的两个源头(一次是第一次的时候标记的,一次是第二次过来的)连一条边。

这样最多连m(位数)*n条边,实际上比这个值更小。

这种做法可以将很多显然不会出现在最小生成树里的边排除掉。

opencup的标程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
// O(kn)

#include <bits/stdc++.h>

using namespace std;


struct FAU {
    vector <int> p, r;

    FAU(int n): p(n,-1), r(n,0) {}

    int find(int x) {
        if (p[x] == -1) return x;
        return p[x] = find(p[x]);
    }

    void join(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) return ;

        if (r[x] > r[y]) p[y] = x;
        else p[x] = y;

        if (r[x] == r[y]) ++r[y];
    }
};

int readBinary() {
    string s;
    cin >> s;
    
    int result = 0;
    for (char c : s) {
        result = 2 * result + ((c == 'L') ? 1 : 0);
    }
    
    return result;
}

void solveTestcase() {
    int k, n;
    cin >> k >> n;

    const int N = 1 << k;
    
    vector <int> dist(N, -1), from(N);
    queue <int> q;
    
    for (int i = 0; i < n; i++) {
        int val = readBinary();
        
        dist[val] = 0;
        from[val] = i;
        
        q.push(val);
    }
    
    vector <vector <pair<int,int>>> edges(k+1);
    
    while (!q.empty()) {
        int v = q.front(); q.pop();
        
        for (int bit = 0; bit < k; bit++) {
            int u = v ^ (1 << bit);
            
            if (dist[u] == -1) {
                dist[u] = 1 + dist[v];
                from[u] = from[v];
                
                q.push(u);
            } else if (from[u] != from[v]) {
                int len = dist[u] + dist[v] + 1;
                
                if (len <= k) {
                    edges[len].push_back({from[u], from[v]});
                }
            }
        }
    }
    
    FAU fau(n);
    int ans = 0;
    
    for (int len = 1; len <= k; len++) for (auto &edge : edges[len]) {
        if (fau.find(edge.first) != fau.find(edge.second)) {
            ans += len;
            fau.join(edge.first, edge.second);
        }
    }
    
    cout << ans << '\n';
}

int main() {
    ios_base::sync_with_stdio(false);
    
    int z;
    cin >> z;
    
    while (z--) {
        solveTestcase();
    }
    
    return 0;
}
posted @ 2018-04-15 20:45  AutSky_JadeK  阅读(335)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト