2016多校训练Abandoned country (最小生成树+期望)

题目需要我们求把所有城市连起来用到的最小路程,和选择任意两点的路程和除以总对点数就是期望了

所以我们要用最小生成树求最小路程,再遍历找每一条边的子节点个数,用公式(子节点的个数)*(总节点数-子节点数)就是该边在期望中贡献的次数,再乘边长就行了。

Abandoned country

Time Limit : 8000/4000ms (Java/Other)   Memory Limit : 65536/65536K (Java/Other)
Total Submission(s) : 93   Accepted Submission(s) : 24
Font: Times New Roman | Verdana | Georgia
Font Size: ← →

Problem Description

An abandoned country has n(n100000) villages which are numbered from 1 to n. Since abandoned for a long time, the roads need to be re-built. There are m(m1000000) roads to be re-built, the length of each road is wi(wi1000000). Guaranteed that any two wi are different. The roads made all the villages connected directly or indirectly before destroyed. Every road will cost the same value of its length to rebuild. The king wants to use the minimum cost to make all the villages connected with each other directly or indirectly. After the roads are re-built, the king asks a men as messenger. The king will select any two different points as starting point or the destination with the same probability. Now the king asks you to tell him the minimum cost and the minimum expectations length the messenger will walk.

Input

The first line contains an integer T(T10) which indicates the number of test cases.

For each test case, the first line contains two integers n,m indicate the number of villages and the number of roads to be re-built. Next m lines, each line have three number i,j,wi, the length of a road connecting the village i and the village j is wi.

Output

output the minimum cost and minimum Expectations with two decimal places. They separated by a space.

Sample Input

1
4 6
1 2 1
2 3 2
3 4 3
4 1 4
1 3 5
2 4 6

Sample Output

6 3.33

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define INF 999999999
#define LL long long
#define mod 1000003
#define maxn 1000005
using namespace std;
int p[100005];
int n, m;
struct Edge
{
    int from, to;
    LL dist;
    Edge() {}
    Edge(int u, int v, LL d) :from(u), to(v), dist(d) {};
};
vector<Edge> edges;
vector<int> G[100005];
int mm;
struct node
{
    int u, v;
    LL w;
};
node poi[1000005];
void AddEdge(int from, int to, LL dist)
{
    edges.push_back(Edge(from, to, dist));
    G[from].push_back(mm++);
}
int cmp(node a, node b)
{
    return a.w<b.w;
}
int find(int x)//并查集+路径压缩
{
    int r = x;
    while (p[r] != r)
        r = p[r];
    int i = x, j;
    while (i != r)
    {
        j = p[i];
        p[i] = r;
        i = j;
    }
    return r;
}
LL kru()//运用紫书的方法竟然超时,最后学了大神的方法
{
    LL ans = 0;
    int cnt = 0;
    for (int i = 0; i <= n; i++) p[i] = i;
    sort(poi, poi + m, cmp);
    for (int i = 0; i<m; i++)
    {
        int x = find(poi[i].u);
        int y = find(poi[i].v);
        if (x != y)
        {
            AddEdge(poi[i].u, poi[i].v, poi[i].w);
            AddEdge(poi[i].v, poi[i].u, poi[i].w);
            ans += poi[i].w;
            p[x] = y;
            if (++cnt >= n - 1)
                break;
        }
    }
    return ans;
}
int siz[100005];
double dasiz[100005];
void dfs(int root, int fa)//深搜递归每个节点
{
    siz[root] = 1;
    for (int i = 0; i <G[root].size(); i++)
    {
        Edge &ee = edges[G[root][i]];
        LL len = ee.dist;
        int son = ee.to;
        if (son == fa)
            continue;
        dfs(son, root);
        siz[root] += siz[son];
        dasiz[root] += dasiz[son] + (LL)siz[son] * (LL)(n - siz[son])*(double)len;
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        mm = 0;
        int ff = 0;
        scanf("%d%d", &n, &m);
        if (m == 0)
            ff = 1;
        for (int i = 0; i<m; i++)
        {
            scanf("%d %d %I64d", &poi[i].u, &poi[i].v, &poi[i].w);
        }
        LL sum = kru();
        memset(siz, 0, sizeof(siz));
        memset(dasiz, 0, sizeof(dasiz));
        dfs(1, -1);
        LL tti = (LL)(n - 1)*(LL)n;//n是整型,必须转化为LL,要不会爆int
        LL ti = tti / 2;
        printf("%I64d", sum);
        if (ff == 0)
            printf(" %.2lf\n", (double)dasiz[1] / ti);
        else
            printf(" 0.00\n");
        for (int i = 0; i <= n; i++)
        {
            G[i].clear();
        }
        edges.clear();
    }
}


<think>我们正在讨论的是数据库连接池中的`remove-abandoned-timeout`配置,特别是当活动线程(连接)数量小于最小连接数(min-idle)时,该机制是否会回收连接。 首先,需要明确`remove-abandoned-timeout`机制的核心目标:它用于回收那些被应用程序获取但长时间未被归还的连接(即“废弃连接”),以防止连接泄漏。这种回收行为主要关注连接是否超时未归还,而不是当前连接池中的连接数量。 关键点: 1. **回收条件**:当一个连接被应用程序借用(borrow)后,如果在`remove-abandoned-timeout`设定的时间内没有被归还(即没有调用`close()`方法归还到连接池),则该连接会被标记为废弃并强制关闭回收。 2. **触发时机**:废弃连接的回收通常发生在连接池需要创建新连接时(例如当活动连接数接近最大值,且空闲连接不足)[^1],或者由连接池的后台清理线程定期扫描(具体实现可能因连接池而异)。 3. **与最小连接数(min-idle)的关系**:最小连接数(min-idle)是指连接池始终保持的最小空闲连接数。无论活动连接数是否低于min-idle,只要某个连接被借用且超过`remove-abandoned-timeout`时间未归还,它就会被回收。这是因为废弃连接回收机制独立于连接池的常规空闲连接维护(如min-idle的保持)。 因此,回答用户的问题: - **当活动线程(连接)数量小于最小连接数时,`remove-abandoned-timeout`机制是否回收连接?** - **会回收**。只要一个连接被应用程序占用且超过设定时间未归还,无论当前连接池的活动连接数少(即使小于min-idle),该连接都会被强制回收。这是因为废弃连接回收的判断标准是“占用时间是否超时”,与连接池的当前状态无关。 补充说明: - 回收废弃连接后,连接池可能会创建新连接来满足min-idle的要求(如果当前空闲连接数低于min-idle)。但这是连接池的常规维护行为,与废弃连接回收机制是独立的。 - 示例:假设min-idle=5,当前活动连接数为3(均未超时),空闲连接数为5,此时不会触发废弃连接回收。但若其中一个活动连接占用时间超过`remove-abandoned-timeout`,则它会被回收,导致活动连接数降为2。随后,连接池可能因空闲连接数不足5而创建新连接以补充到min-idle。 总结:`remove-abandoned-timeout`机制只关注单个连接的占用时间是否超时,不受连接池当前活动连接数或空闲连接数的影响(包括是否低于min-idle)。因此,即使活动连接数小于min-idle,超时的废弃连接仍会被回收。 为了更清晰地说明,我们可以用一个表格对比不同情况: | 场景描述 | 是否触发废弃连接回收 | |-------------------------------------------|----------------------| | 活动连接数 > min-idle,有连接超时未归还 | 是 | | 活动连接数 = min-idle,有连接超时未归还 | 是 | | **活动连接数 < min-idle,有连接超时未归还** | **是** | | 活动连接数任意,所有连接均在超时时间内归还 | 否 | §§相关问题§§ 1. 连接池的最小空闲连接数(min-idle)与最大连接数(max-active)如何配置最优? 2. 如何监控和识别数据库连接泄漏? 3. 除了`remove-abandoned-timeout`,还有哪些防止连接泄漏的策略? </think>### `remove-abandoned-timeout` 回收机制与最小连接数关系分析 #### **核心结论** 当活动线程数**小于最小连接数**时,**仍会触发废弃连接回收**。`remove-abandoned-timeout` 的回收机制与连接数状态无关,仅取决于连接是否超时未归还[^4]。 --- #### **机制详解** 1. **回收触发条件** `remove-abandoned-timeout` 的回收逻辑**不受当前连接数影响**,只要满足以下两个条件即触发回收: - 连接被应用程序占用时间超过设定阈值(如 `120s`) - 连接池开启废弃检测(`remove-abandoned=true`)[^1][^4] *示例:即使当前只有 1 个活动连接(小于 `min-idle=10`),若其占用超时仍会被强制关闭。* 2. **与最小连接数的独立关系** - `min-idle`(最小空闲连接)仅控制连接池的**保底空闲连接数** - 废弃连接回收是**独立运行的异常处理机制**,目的是防止连接泄漏 - 两者关系可概括为: $$回收机制 \parallel 连接数维护$$ (并行独立运作) 3. **回收后的补偿机制** 当废弃连接被回收后: - 若空闲连接数低于 `min-idle`,连接池会**立即创建新连接补齐** - 若空闲连接充足,则维持当前状态 *(该过程与回收动作解耦)* --- #### **配置验证示例** 参考典型配置[^4]: ```properties spring.datasource.min-idle=10 # 最小空闲连接 spring.datasource.remove-abandoned=true spring.datasource.remove-abandoned-timeout=60 # 60秒超时回收 ``` **运行场景**: 1. 当前活动连接数:5(小于 `min-idle=10`) 2. 其中 1 个连接执行耗时操作超过 60 秒 3. **结果**: - 超时连接被强制回收 - 连接池检测到空闲连接数=9(低于 `min-idle`) - **自动创建 1 个新连接补齐至 10 个空闲连接** --- #### **注意事项** 1. **误回收风险** 长时间查询(如报表生成)可能被误回收,建议生产环境设置更高阈值(如 `120s`[^1])并启用 `log-abandoned=true` 记录堆栈[^4]。 2. **性能影响** 频繁回收可能增加 CPU 开销,需配合 `time-between-eviction-runs-millis` 控制检测频率。 3. **连接泄漏根本解决** 回收机制是**兜底方案**,仍需在代码中确保 `try-with-resources` 或显式调用 `close()`[^3]: ```java try (Connection conn = dataSource.getConnection()) { // 自动关闭 // 业务逻辑 } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值