2020 ICPC Taipei H. Optimización para UltraNet (dos puntos + árbol de expansión mínimo)

Significado de la pregunta: Para  encontrar un árbol de expansión que sea tan largo  , primero satisfaga que el lado más corto sea el más grande y, en segundo lugar, haga la suma del lado más corto en la ruta de los dos puntos más pequeños.

Idea: Para maximizar el lado más corto, considere indicar el lado más corto para determinar si se puede generar un árbol. Si es posible, considere minimizar la suma de los lados más cortos en cualquier camino de dos puntos, es decir, los lados restantes deben ser tan pequeños lo más pequeño posible, es decir, encuentre el árbol de expansión mínimo. Después de construir el mapa, ejecute la suma del lado más corto de dos puntos en el camino.

referencia

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 27;
const int N = 2e4 + 7;
const int M = 1e6 + 7;

int n, m;
int head[N], tot, nxt[N], to[N], val[N], fa[N], siz[N];
int mi, id, X, Y;
bool vis[N];

struct Edge {
    int u, v, w;
    bool operator < (const Edge &a) const {
        return w < a.w;
    }
} edge[M];

void addedge(int u, int v, int w) {
    to[++tot] = v;
    nxt[tot] = head[u];
    val[tot] = w;
    head[u] = tot;
}

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

bool Union(int x, int y) {
    int xx = Find(x);
    int yy = Find(y);
    if(xx != yy) {
        fa[xx] = yy;
        return 1;
    }
    return 0;
}

void get(int x, int fa) {
    siz[x] = 1;
    for(int i = head[x]; i; i = nxt[i]) {
        int v = to[i], w = val[i];
        if(vis[i] || v == fa) continue;
        get(v, x);
        siz[x] += siz[v];
        if(w < mi) {
            mi = w;
            id = i;
            Y = v, X = x;
        }
    }
}

ll dfs(int x) {
    bool flag = 0;
    for(int i = head[x]; i; i = nxt[i]) {
        if(vis[i]) continue;
        flag = 1;
        break;
    }
    if(!flag) return 0;
    mi = 1e9, id = 0;
    get(x, -1);
    vis[id] = 1, vis[id ^ 1] = 1;
    ll num = 1ll * (siz[x] - siz[Y]) * siz[Y] * mi;
    int _x = X, _y = Y;
    return num + dfs(_x) + dfs(_y);
}

bool check(int pos, bool flag) {
    for(int i = 1; i <= n; ++i) fa[i] = i;
    int cnt = 0;
    for(int i = pos; i <= m; ++i) {
        int xx = Find(edge[i].u);
        int yy = Find(edge[i].v);
        int w = edge[i].w;
        if(Union(xx, yy)) {
            ///只对最后一次建图
            if(flag) {
                addedge(edge[i].u, edge[i].v, w);
                addedge(edge[i].v, edge[i].u, w);
            }
            cnt++;
        }
        if(cnt >= n - 1) return 1;
    }
    return 0;
}

int lower_bound(int l, int r) {
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if (check(mid, 0)) l = mid;
        else r = mid - 1;
    }
    return l;
}

int main() {
    tot = 1;
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++i)
        scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
    sort(edge + 1, edge + m + 1);
    int minn = lower_bound(1, m);
    check(minn, 1);
    printf("%lld\n", dfs(1));
    return 0;
}

 

Supongo que te gusta

Origin blog.csdn.net/weixin_43871207/article/details/112975613
Recomendado
Clasificación