蓝桥杯——算法提高 最小方差生成树

一、思路

  枚举所有生成树的边权和值,对每一个枚举的边权和值sum,修改所有边的边权为(es[i].cost - sum * 1.0 / (N - 1))2,即方差公式的分子,然后跑最小生成树算法,同时记录边的原来的权值和,如果求出的“最小方差”生成树的边权值和为sum,那么,用这个"最小方差"去更新答案。

二、复杂度分析

  时间复杂度:O(N * W * M * logM)。N * W为枚举边权和值的时间。边权和值最小为0,最大为(N - 1) * W。

三、PS

  这题据说蓝桥杯官网数据有问题。有5个样例(2、3、4、5、6),总是WA。所以,正确的代码也只能得50分。

四、源代码

#include<bits/stdc++.h>
using namespace std;
int N, M;
const int MAXN = 55, MAXM = 1010;
const double INF = (1LL << 60) * 1.0;
typedef struct Edge0 {
    int u, v, oldcost;
    double newcost;
    bool operator < (Edge0 e) const {
        return newcost < e.newcost;
    }
    void assgin(int _u, int _v, int _cost) {
        u = _u;
        v = _v;
        oldcost = _cost;
    }
} Edge;
Edge edges[MAXM];

template <class T> inline void read(T &x) {
    int t;
    bool flag = false;
    while((t = getchar()) != ‘-‘ && (t < ‘0‘ || t > ‘9‘)) ;
    if(t == ‘-‘) flag = true, t = getchar();
    x = t - ‘0‘;
    while((t = getchar()) >= ‘0‘ && t <= ‘9‘) x = x * 10 + t - ‘0‘;
    if(flag) x = -x;
}

/**并查集部分*/
int par[MAXN], rank[MAXN];
void init_ufind() {
    for(int i = 0; i < MAXN; ++i) {
        par[i] = i;
        rank[i] = 0;
    }
}

int ufind(int x) {
    return x == par[x] ? x : par[x] = ufind(par[x]);
}

void unite(int x, int y) {
    x = ufind(x), y = ufind(y);
    if(x == y)return;
    if(rank[x] < rank[y])par[x] = y;
    else {
        par[y] = x;
        if(rank[x] == rank[y])rank[x]++;
    }
}

bool same(int x, int y) {
    return ufind(x) == ufind(y);
}
/**并查集部分*/

double kruscal(int tot) {
    double avg = tot * 1.0 / (N - 1);
    for(int i = 0; i < M; ++i) {
        edges[i].newcost = (edges[i].oldcost * 1.0 - avg) * (edges[i].oldcost * 1.0 - avg);
    }
    sort(edges, edges + M);
    init_ufind();
    double res = 0;
    int ires = 0;
    for(int i = 0; i < M; ++i) {
        Edge& e = edges[i];
        if(!same(e.u, e.v)) {
            unite(e.u, e.v);
            res += e.newcost;
            ires += e.oldcost;
        }
    }
    if(ires == tot)return res / (N - 1);
    else return INF;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif
    int T = 1, a, b, c;
    int costs[MAXM];
    while(scanf("%d%d", &N, &M), !(N == 0 && M == 0)) {
        for(int i = 0; i < M; ++i) {
            read(a), read(b), read(c);
            edges[i].u = a, edges[i].v = b, edges[i].oldcost = c;
            costs[i] = c;
        }
        sort(costs, costs + M);
        int mintot = 0, maxtot = 0;
        for(int i = 0;i < N - 1;++i)mintot += costs[i];
        for(int i = M - 1;i > M - N;--i)maxtot += costs[i];
        double ans = INF;
        for(int tot = mintot; tot <= maxtot; ++tot) {
            ans = min(ans, kruscal(tot));
        }
        printf("Case %d: %.2f\n", T++, ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/565261641-fzh/p/8284533.html

时间: 2024-11-05 20:42:01

蓝桥杯——算法提高 最小方差生成树的相关文章

算法笔记_164:算法提高 最小方差生成树(Java)

目录 1 问题描述 2 解决方案   1 问题描述 问题描述 给定带权无向图,求出一颗方差最小的生成树. 输入格式 输入多组测试数据.第一行为N,M,依次是点数和边数.接下来M行,每行三个整数U,V,W,代表连接U,V的边,和权值W.保证图连通.n=m=0标志着测试文件的结束. 输出格式 对于每组数据,输出最小方差,四舍五入到0.01.输出格式按照样例. 样例输入 4 51 2 12 3 23 4 24 1 12 4 34 61 2 12 3 23 4 34 1 12 4 31 3 30 0 样

蓝桥杯 算法提高 道路和航路 满分AC ,SPFA算法的SLF优化,测试数据还是比较水的,貌似没有重边

算法提高 道路和航路 时间限制:1.0s   内存限制:256.0MB 问题描述 农夫约翰正在针对一个新区域的牛奶配送合同进行研究.他打算分发牛奶到T个城镇(标号为1..T),这些城镇通过R条标号为(1..R)的道路和P条标号为(1..P)的航路相连. 每一条公路i或者航路i表示成连接城镇Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代价为Ci.每一条公路,Ci的范围为0<=Ci<=10,000:由于奇怪的运营策略,每一条航路的Ci可能为负的,也就是-10,000

蓝桥杯 算法提高 学霸的迷宫 经典BFS问题

算法提高 学霸的迷宫 时间限制:1.0s   内存限制:256.0MB 问题描述 学霸抢走了大家的作业,班长为了帮同学们找回作业,决定去找学霸决斗.但学霸为了不要别人打扰,住在一个城堡里,城堡外面是一个二维的格子迷宫,要进城堡必须得先通过迷宫.因为班长还有妹子要陪,磨刀不误砍柴功,他为了节约时间,从线人那里搞到了迷宫的地图,准备提前计算最短的路线.可是他现在正向妹子解释这件事情,于是就委托你帮他找一条最短的路线. 输入格式 第一行两个整数n, m,为迷宫的长宽. 接下来n行,每行m个数,数之间没

蓝桥杯 算法提高 6-17 复数四则运算

算法提高 6-17复数四则运算 时间限制:1.0s   内存限制:512.0MB 设计复数库,实现基本的复数加减乘除运算. 输入时只需分别键入实部和虚部,以空格分割,两个复数之间用运算符分隔:输出时按a+bi的格式在屏幕上打印结果.参加样例输入和样例输出. 注意考虑特殊情况,无法计算时输出字符串"error". 样例输入 2 4 * -3 2 样例输出 -14-8i 样例输入 3 -2 + -1 3 样例输出 2+1i 1 #include<iostream> 2 #inc

蓝桥杯 算法提高 8皇后&#183;改 -- DFS 回溯

  算法提高 8皇后·改   时间限制:1.0s   内存限制:256.0MB 问题描述 规则同8皇后问题,但是棋盘上每格都有一个数字,要求八皇后所在格子数字之和最大. 输入格式 一个8*8的棋盘. 输出格式 所能得到的最大数字和 样例输入 1 2 3 4 5 6 7 89 10 11 12 13 14 15 1617 18 19 20 21 22 23 2425 26 27 28 29 30 31 3233 34 35 36 37 38 39 4041 42 43 44 45 46 47 48

蓝桥杯-算法提高-日期计算

算法提高 日期计算 时间限制:1.0s   内存限制:256.0MB 问题描述 已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况.尤其是逢百年不闰,逢400年闰的情况. 输入格式 输入只有一行 YYYY MM DD 输出格式 输出只有一行 W 数据规模和约定 1599 <= YYYY <= 2999 1 <= MM <= 12 1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期 1 <= W &

蓝桥杯 算法训练 最小乘积(基本型) (水题,排序)

算法训练 最小乘积(基本型) 时间限制:1.0s   内存限制:512.0MB 问题描述 给两组数,各n个. 请调整每组数的排列顺序,使得两组数据相同下标元素对应相乘,然后相加的和最小.要求程序输出这个最小值. 例如两组数分别为:1 3 -5和-2 4 1 那么对应乘积取和的最小值应为: (-5) * 4 + 3 * (-2) + 1 * 1 = -25 输入格式 第一个行一个数T表示数据组数.后面每组数据,先读入一个n,接下来两行每行n个数,每个数的绝对值小于等于1000. n<=8,T<=

蓝桥杯- 算法提高 逆序排列

算法提高 逆序排列 时间限制:1.0s   内存限制:512.0MB 问题描述 编写一个程序,读入一组整数(不超过20个),并把它们保存在一个整型数组中.当用户输入0时,表示输入结束.然后程序将把这个数组中的值按逆序重新存放,并打印出来.例如:假设用户输入了一组数据:7 19 -5 6 2 0,那么程序将会把前五个有效数据保存在一个数组中,即7 19 -5 6 2,然后把这个数组中的值按逆序重新存放,即变成了2 6 -5 19 7,然后把它们打印出来. 输入格式:输入只有一行,由若干个整数组成,

蓝桥杯- 算法提高 最大乘积

算法提高 最大乘积 时间限制:1.0s   内存限制:512.0MB 问题描述 对于n个数,从中取出m个数,如何取使得这m个数的乘积最大呢? 输入格式 第一行一个数表示数据组数 每组输入数据共2行: 第1行给出总共的数字的个数n和要取的数的个数m,1<=n<=m<=15, 第2行依次给出这n个数,其中每个数字的范围满足:a[i]的绝对值小于等于4. 输出格式 每组数据输出1行,为最大的乘积. 样例输入 15 51 2 3 4 2 样例输出 48 #include<iostream&