UESTC 1641 此情无计可消除,才下眉头,却上心头。

本文介绍了一种解决ACM竞赛中特定问题的方法,通过构建包含n+1个虚拟点的图并使用最小生成树算法来确定获得序列值所需的最少询问次数。详细解释了算法流程与实现,并提供了完整的C++代码。

题目链接:http://acm.uestc.edu.cn/#/problem/show/1641

题解:
建立n+1个虚拟点0到n,对于询问区间[l,r],在l-1与r之间连边,边权为C[l][r]
那么能得到该序列的极小询问集合会构成这n+1个点的一个生成树,代价为边权和
证明(?):
要得到n个位置的值,至少要询问n次
若询问集合构成的图存在回路
那么该回路对应的询问子集中任意一个询问的结果都可以由其它询问得到
故询问集合构成的图有n条边且没有回路
也就是这n+1个点的一个生成树
所以对这n+1个点跑一遍最小生成树即可
时间复杂度:O(n^2)
空间复杂度:O(n^2)

//UESTC 1641

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int maxm = 1000010;
int fa[maxn];
struct edge{
    int u, v, w;
    edge(){}
    edge(int u, int v, int w):u(u),v(v),w(w){}
}E[maxm];
int find_set(int x){
    if(x==fa[x]) return x;
    else return fa[x] = find_set(fa[x]);
}
void union_set(int x, int y){
    int fx = find_set(x), fy = find_set(y);
    if(fx!=fy){
        fa[fx]=fy;
    }
}
bool cmp(edge a, edge b){
    return a.w<b.w;
}
int n, x, cnt;

int main()
{
    scanf("%d", &n);
    for(int i=0; i<=n; i++) fa[i]=i;
    cnt = 0;
    for(int i=1; i<=n; i++){
        for(int j=i; j<=n; j++){
            scanf("%d", &x);
            E[++cnt]={i-1, j, x};
        }
    }
    int ans = 0;
    sort(E+1, E+cnt+1, cmp);
    int edgecnt = 0;
    for(int i=1; i<=cnt; i++){
        int x = find_set(E[i].u), y = find_set(E[i].v);
        if(x != y){
            fa[x] = y;
            ans += E[i].w;
            edgecnt++;
            if(edgecnt==n) break;
        }
    }
    printf("%d\n", ans);
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值