文章标题 CSU 1845: Sensor network (暴力LCA+kruskal思想)

本文介绍了一种寻找边权极差最小生成树的问题解决方法,通过贪心策略结合Kruskal算法思想,实现了对传感器网络中最优电压分配方案的求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1845: Sensor network

链接 1845: Sensor network
题意: 给出一些传感器以及他们连接起来的网络,每个传感器都有其额 定电压,要求通过的电压只能高不能低。现在只能在一个传感器 上施加电压,然后问如果要使得网络中的每个点都能够有电,这 样的一个网络中各个传感器之间的极差最小是多少。
分析:很显然的,要使得网络中的每一个点都连通电,必须要连上n-1条边。然后 求连的所有边的边权的极差最小,我们没有必要把多余的边添加进来,即直 接判断生成树的极差即可。问题变为了找一棵边权极差最小的生成树。 根据贪心的思想,我们首先要像kruskal那样对所有边按照边权值来排序,排 序之后,连续的几条边如果构成生成树,那么这棵生成树的极差就是备选解。 即不用考虑非连续的情况,因为非连续情况一定有比他更优的解。这样,我 们只需要枚举这个连续的区间了。我们设定一个集合f,边按照从小到大的顺 序依次次检索,如果该边连接的两点不连通,即不构成环,那么我们连这条 边,并把边加入集合f。如果两点已经连通,那么,删除两点路径上边权最小 的边,然后再连上这条边。当集合的大小为n-1时,说明已经构成了一棵生 成树,那么我们把备选解与最终解进行比较即可。
代码:

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <math.h>
#include <algorithm>
using namespace std;

int n,m;

struct Edge{
    int u,v;
    int val;
};
bool cmp(Edge a,Edge b){
    return a.val<b.val;
}
Edge edge[355*355/2];


vector<int>q,G[500];
int fa[500];
int mp[500][500];//mp[i][j]来保存i-->j的权值 
int num[500][500];//用num[i][j]来标记i-->j是第几条边 

void dfs(int u){//通过dfs来求父节点 
    for (int i=0;i<G[u].size();i++){
        if (fa[G[u][i]]==0){
            fa[G[u][i]]=u;//父节点为u 
            dfs(G[u][i]);
        }
    }
}

int LCA(int u,int v){
    for (int i=0;i<=n;i++){
        fa[i]=0;
        G[i].clear();
    }
    //从已经选择的边来构图找最小的边 
    for (int i=0;i<q.size();i++){
        int x=edge[q[i]].u;
        int y=edge[q[i]].v;
        G[x].push_back(y);
        G[y].push_back(x); 
    }
    fa[v]=-1;
    dfs(v);
    if (!fa[u]) return -1;//相当于u,v不在一个连通块中,直接返回-1 
    int ans=1e9;
    int place=-1;
    while (u!=v){//找u-->v路径上的权值最小的边 
        if (ans>mp[u][fa[u]]){
            ans=mp[u][fa[u]]; 
            place=num[u][fa[u]];
        }
        u=fa[u]; 
    }
    return place;//将最短的边返回去 
}

int main()
{
    while (scanf ("%d",&n)){
        if (n==0)break;
        scanf ("%d",&m);
        for (int i=0;i<m;i++){
            scanf ("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].val);
            edge[i].u++;edge[i].v++;
            mp[edge[i].u][edge[i].v]=edge[i].val;//保存权值 
            mp[edge[i].v][edge[i].u]=edge[i].val; 
        }
        sort(edge,edge+m,cmp);
        q.clear();
        int ans=1e9;
        for (int i=0;i<m;i++){
            num[edge[i].u][edge[i].v]=i;//保存边的编号 
            num[edge[i].v][edge[i].u]=i;
            int place=LCA(edge[i].u,edge[i].v);
            if (place>=0){//产生连通,则去掉最小的权值的一条边 
                vector<int>::iterator iter;
                iter=lower_bound(q.begin(),q.end(),place);//二分找到place的位置 
                q.erase(iter);
            }
            q.push_back(i);
            if (q.size()==n-1){
                ans=min(ans,edge[i].val-edge[q[0]].val);
            }
        }
        printf ("%d\n",ans);
    } 
    return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值