【Day8】一名菜鸟ACMer的暑假训练

【Day8】一名菜鸟ACMer的暑假训练

  1. 上午补了昨晚AtCoder的题解(目前只做到E)
    (博客+视频)
  2. 下午在做一道别人问的题目,搞了好久。以及和佬探讨一道cf,目前是有了一个思路,但是由于我码力低下还没整出来
  3. 剩下的时间除了摸鱼,只做了几道kuangbin
    (感觉最小生成树做起来顺了一些,也有可能是有了最短路的铺垫)
  4. 打 Codeforces Round #805 (Div. 3)

AcWing 4291. 丛林之路

#include <bits/stdc++.h>

using namespace std;
const int N = 30, M = 80;
int n, k;
int fa[M];

struct Node {
    int a, b, w;
    bool operator<(const Node &t) const {
        return w < t.w;
    }
}e[M << 1];

void init () {
    for (int i = 0; i <= n; i ++)
        fa[i] = i;
}

int find (int x) {
    if (x != fa[x])
        fa[x] = find (fa[x]);
    return fa[x];
}

int kruscal () {
    //保证连通
    init ();
    sort (e, e + k);
    int ans = 0;
    for (int i = 0; i < k; i ++) {
        int a = e[i].a, b = e[i].b, w = e[i].w;
        a = find (a), b = find(b);
        if (a != b) {
            fa[a] = b;
            ans += w;
        }
    }
    return ans;
}

int main () {
    while (cin >> n, n) {
        k = 0, n --;
        for (int i = 0; i < n; i ++) {
            char id;    cin >> id;
            int a = id - 'A';
            int m;  cin >> m;
            while (m --) {
                int w;
                cin >> id >> w;
                int b = id - 'A';
                e[k++] = {a, b, w}, e[k++] = {b, a, w};               
            }
        }
        cout << kruscal () << endl;
    }
}

AcWing 4292. 网络连接

水水水

#include<bits/stdc++.h>

using namespace std;
const int N = 55, M = 1505;
int n, m, k;
int fa[N];

struct Node {
    int a, b, w;
    bool operator<(const Node &t) const {
        return w < t.w;
    }
}e[M << 1];

void init () {
    for (int i = 1; i <= n; i ++)
        fa[i] = i;
}

int find (int x) {
    if (x != fa[x])
        fa[x] = find (fa[x]);
    return fa[x];
}

int kruscal () {
    init ();
    sort (e, e + k);
    int ans = 0;
    for (int i = 0; i < k; i ++) {
        int a = e[i].a, b = e[i].b, w = e[i].w;
        a = find (a), b = find (b);
        if (a != b) {
            fa[a] = b;
            ans += w;
        }
    }
    return ans;
}

int main () {
    while (cin >> n, n) {
        cin >> m;
        k = 0;
        while (m --) {
            int a, b, w;
            cin >> a >> b >> w;
            // bool flag = true;
            // for (int i = 0; i < k; i ++) {
            //     if (e[i].a == a && e[i].b == b && e[i].w < w) {
            //         flag = false;
            //         break;
            //     }
            // }
            // if (flag)   
            e[k ++] = {a, b, w}, e[k ++] = {b, a, w};
        }
        cout << kruscal () << endl;
    }
}

//图中可能存在重边。

AcWing 4293. 建造空间站

抽象建图:
对于本来就已经相交或相切的圆,建一条权值为0的边;
对于相离的圆,边权为\(|O_1 O_2|-r_1-r_2\)
建完图之后,跑最小生成树即可
注意一些double的问题

#include <bits/stdc++.h>

using namespace std;
const int N = 105;
int n, k;
int fa[N];

struct zuobiao {
    double x, y, z, r;
}a[N];

struct Node {
    int a, b;
    double w;
    bool operator < (const Node &t) const {
        return w < t.w;
    }
}e[N*N*2];

void init () {
    for (int i = 1; i <= N; i ++) //注意这里的更新是N
        fa[i] = i;
}

int find (int x) {
    if (x != fa[x])
        fa[x] = find (fa[x]);
    return fa[x];
}

double kruscal () {
    init ();
    sort (e, e + k);
    double ans = 0;
    for (int i = 0; i < k; i ++) {
        int a = e[i].a, b = e[i].b;
        double w = e[i].w; //分开来!!
        a = find (a), b = find (b);
        if (a != b) {
            fa[a] = b;
            ans += w;
        }
    }
    return ans;
}

int main () {
    int n;
    while (cin >> n , n) {
        k = 0;
        for (int i = 1; i <= n; i ++) {
            double x, y, z, r;
            cin >> x >> y >> z >> r;
            a[i] = {x, y, z, r};
        }
        for (int i = 1; i <= n; i ++)
            for (int j = i + 1; j <= n; j ++) {
                double x = a[i].x, y = a[i].y, z = a[i].z, r = a[i].r;
                double xx = a[j].x, yy = a[j].y, zz = a[j].z, rr = a[j].r;
                double d1 = (x-xx)*(x-xx) + (y-yy)*(y-yy) + (z-zz)*(z-zz), d2 = r + rr;
                if (d1 <= d2*d2)   e[k ++] = {i, j, 0}, e[k ++] = {j, i, 0};
                else {
                    double w = sqrt (d1) - d2;
                    e[k ++] = {i, j, w}, e[k ++] = {j, i, w};
                }
            }

        cout << fixed << setprecision(3) << kruscal () << endl;
    }
}
//维系两个相离的球的通道长度为|AB|-r1-r2
//相交或相切就建一条为0的边
//然后跑最小生成树

AcWing 4294. 修建道路

和上一题真的蛮像的
就是已有的边权值为0,然后没连上的就加权值

#include <bits/stdc++.h>

using namespace std;
const int N = 105, M = N*N*2;
int n, m, k;
bool st[N][N]; //表示已有边
int dis[N][N], fa[N];

struct Node {
    int a, b, w;
    bool operator< (const Node &t) const {
        return w < t.w;
    }
}e[M];

void init () {
    for (int i = 1; i <= N; i ++)   fa[i] = i;
}

int find (int x) {
    if (x != fa[x])
        fa[x] = find (fa[x]);
    return fa[x];
}

int kruscal () {
    init ();
    sort (e, e + k);
    int ans = 0;
    for (int i = 0; i < k; i ++) {
        int a = e[i].a, b = e[i].b, w = e[i].w;
        a = find (a), b = find (b);
        if (a != b) {
            fa[a] = b;
            ans += w;
        }
    }
    return ans;
}

int main () {
    cin >> n;
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++) 
            cin >> dis[i][j];

    cin >> m;
    while (m --) {
        int a, b;
        cin >> a >> b;
        st[a][b] = st[b][a] = true;
    }

    for (int i = 1; i <= n; i ++)
        for (int j = i + 1; j <= n; j ++) {
            if (st[i][j] || st[j][i])   e[k++] = {i, j, 0}, e[k++] = {j, i, 0};
            //需要自己建边
            else    e[k++] = {i, j, dis[i][j]}, e[k++] = {j, i, dis[j][i]};
        }
    cout << kruscal () << endl;

}
//每个都建边,如果是已有边,则权值为0

AcWing 4295. QS网络

TLE 了哭哭(明天改)

#include <bits/stdc++.h>

using namespace std;
const int N = 505, M = N*N*2;
int n, k;
int p[N], fa[N];

struct Node {
    int a, b, w;
    bool operator < (const Node &t) const {
        return w < t.w;
    }
}e[M];

void init () {
    for (int i = 1; i <= n; i ++)   fa[i] = i;
}

int find (int x) {
    if (x != fa[x]) fa[x] = find (fa[x]);
    return fa[x];
}

int kruscal () {
    init ();
    sort (e, e + k);
    int ans = 0;
    for (int i = 0; i < k; i ++) {
        int a = e[i].a, b = e[i].b, w = e[i].w;
        a = find (a), b  =find (b);
        if (a != b) {
            fa[a] = b;
            ans += w;
        }
    }
    return ans;
}

void solve () {
    k = 0;
    cin >> n;
    for (int i = 1; i <= n; i ++)   cin >> p[i];
    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= n; j ++)  {
            int x;  cin >> x;
            int w = p[i] + p[j] + x;
            e[k ++] = {i, j, w};
        } 
            

    // for (int i = 1; i <= n; i ++)
    //     for (int j = i + 1; j <= n; j ++) {
    //         int w = p[i] + p[j] + dis[i][j];
    //         e[k ++] = {i, j, w}, e[k++] = {j, i, w};
    //     }
    cout << kruscal () << endl;
}

int main () {
    int t;  cin >> t;
    while (t --)    solve ();
}


//不仅有边权还有点权
//直接在建边的时候顺便把点权加到边上

//love so sweet也太好听了!!!
posted @ 2022-07-10 22:07  Sakana~  阅读(34)  评论(0编辑  收藏  举报