zoukankan      html  css  js  c++  java
  • 51nod 1640 天气晴朗的魔法 二分 + 克鲁斯卡算法(kruskal算法) 做复杂了

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1640

    一开始想的时候,看到要使得最大值最小,那这样肯定是二分这个最大值了,然后每一次都跑一次kruskal

    这样的复杂度是O(E * 64),然后被卡TLE了

    然后观察到kruskal的时候,如果最大边是val,那么比val大的是不要的了,然后整个数组也是有序的。

    比如7、6、5、4、3、2、1等,这个也是可以lower_bound的,然后lower_bound后就能过,600ms

    改了lower_bound后,我忘记删除那个if了,居然还是超时。TAT,这数据有点强。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    int n, m;
    const int maxn = 2e5 + 20;
    struct Edge {
        int u, v, w;
        bool operator < (const struct Edge & rhs) const {
            return w > rhs.w;
        }
    }e[maxn];
    int fa[maxn];
    void init() {
        for (int i = 1; i <= n; ++i) fa[i] = i;
    }
    int tofind(int u) {
        if (fa[u] == u) return u;
        else return fa[u] = tofind(fa[u]);
    }
    void tomerge(int x, int y) {
        x = tofind(x);
        y = tofind(y);
        fa[y] = x;
    }
    LL nowAns;
    bool check(LL val) {
        init();
        int sel = 0;
        nowAns = 0;
        struct Edge t;
        t.w = val;
        int pos = lower_bound(e + 1, e + 1 + m, t) - e;
        for (int i = pos; i <= m; ++i) {
    //        if (e[i].w > val) continue;  卡TLE
            if (tofind(e[i].u) == tofind(e[i].v)) continue;
            tomerge(e[i].u, e[i].v);
            nowAns += e[i].w;
            sel++;
            if (sel == n - 1) {
                return true;
            }
        }
        return false;
    }
    void work() {
        scanf("%d%d", &n, &m);
        LL lo = 1e18L, hi = -1e18L;
        for (int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
            lo = min(lo, (LL)e[i].w);
            hi = max(hi, (LL)e[i].w);
        }
        sort(e + 1, e + 1 + m);
        while (lo <= hi) {
            LL mid = (lo + hi) >> 1;
            if (check(mid)) {
                hi = mid - 1;
            } else lo = mid + 1;
        }
        check(lo);
    //    printf("%lld
    ", nowAns);
        cout << nowAns << endl;
    //    struct Edge t;
    //    t.w = 3;
    //    int pos = lower_bound(e + 1, e + 1 + m, t) - e;
    //    cout << pos << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    然后就上网看题解了,然后发现自己做法很复杂了。

    感觉是题意弄得我们想复杂了,又魔法连的值,又总和,

    正解是kruskal两次,第一次就能找出最大值最小,然后从大的再kruskal一次。

    但是为什么还是700ms,有点坑。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    int n, m;
    const int maxn = 2e5 + 20;
    struct Node {
        int u, v, w;
        bool operator < (const struct Node & rhs) const {
            return w < rhs.w;
        }
    }e[maxn];
    bool cmp(struct Node a, struct Node b) {
        return a.w > b.w;
    }
    int fa[maxn];
    int tofind(int u) {
        if (fa[u] == u) return u;
        else return fa[u] = tofind(fa[u]);
    }
    void tomerge(int x, int y) {
        x = tofind(x);
        y = tofind(y);
        fa[y] = x;
    }
    void init() {
        for (int i = 1; i <= n; ++i) fa[i] = i;
    }
    int result() {
        init();
        int sel = 0;
        for (int i = 1; i <= m; ++i) {
            if (tofind(e[i].u) == tofind(e[i].v)) continue;
            tomerge(e[i].u, e[i].v);
            sel++;
            if (sel == n - 1) return e[i].w;
        }
    }
    void work() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        }
        sort(e + 1, e + 1 + m);
        int mx = result();
        sort(e + 1, e + 1 + m, cmp);
        init();
        LL ans = 0;
        int sel = 0;
        for (int i = 1; i <= m; ++i) {
            if (e[i].w > mx) continue;
            if (tofind(e[i].u) == tofind(e[i].v)) continue;
            tomerge(e[i].u, e[i].v);
            sel++;
            ans += e[i].w;
            if (sel == n - 1) break;
        }
        printf("%lld
    ", ans);
    //    cout << ans << endl;
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    PKU_3624(0-1背包)
    背包问题之01背包
    背包问题
    HDU--2602(0-1背包)
    基于baseline、svd和stochastic gradient descent的个性化推荐系统
    基于baseline和stochastic gradient descent的个性化推荐系统
    基于neighborhood models(item-based) 的个性化推荐系统
    基于物品的协同过滤推荐算法——读“Item-Based Collaborative Filtering Recommendation Algorithms”
    基于用户的最近邻协同过滤算法(MovieLens数据集)
    7--操作符重载(1)
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6590869.html
Copyright © 2011-2022 走看看