最小生成树

最小生成树的构建本质

本质
是一个换边的操作。我们考虑原来的一个 nnn个点,mmm条边的图,首先我们不管边权直接构建一个生成树,接着枚举剩下的边,我们发现如果添加上这个边(假如没有重边)一定会形成一个环。

根据最小生成树的定义,我们必须要将这个环上的边权最大的边删去,一直重复这个过程枚举完所有边一定就会构建出一个最小生成树。

假如 uuuvvv之间只有一条路径,那么所求就是 uuuvvv之间的最小边权。

接着我们考虑什么时候u到v存在两条及以上路径——uuuvvv在环上或 uuuvvv之间存在环。
再考虑上文所说的,最小生成树的基本过程是每次构建一个环,接着拆掉最大边权的过程,也就是说原图任意一个环上的最大的边权全都被拆除了,同时因为这个拆除操作会导致 uuuvvv的路径唯一。

最小生成树

定义:包含连通图上所有节点的各边权值总和最小的树

**求法:**将所有点边按权值大小从小到大排列,每次都从中选取最小权值的边(u,v),
并把它添加到正在生长的森林中。森林中的树不断的合并,直到将所有点同属于一棵树为止。(贪心 + 并查集)

1.概述
图的生成树:是它的一颗含有其所有顶点的无环连通子图,一幅加权图的最小生成树(MST)是它的一颗权值(树中的所有边的权值之和)最小的生成树.
2.原理
1.图的一种切分是将图的所有顶点分为两个非空且不重叠的两个集合.
横切边是连接两个属于不同集合的顶点的边.
2.**切分定理:**在一幅加权图中,给定任意的切分,它的横切边中的权重最小者必然属于最小生成树.

PRIM算法:边数较多时使用
(找一点为起点,使所有点串联所连线的权值最小)

#include<iostream>
using namespace std;

#define MAX 100
#define MAXCOST 0x7fffffff

int graph[MAX][MAX];

int Prim(int graph[][MAX], int n)//二维数组作为参数如何使用?
{
    int sta[MAX];//存放某一条边的起点值
    int lowcost[MAX];//存放以i为终点的的边的最小的权值
    int min,minid,sum=0;
    //min用来存放最小权值,minid用来存放权值最小的边所对应的终点
    for(int i=2;i<=n;i++)
    {
        lowcost[i]=graph[1][i];
        //初始化lowcost[i],并把他们的初始值都看作是从节点1出发到i的权值
        sta[i]=1;//起点赋值为1
    }
    sta[1]=0;//节点1进入最小生成树
    for(int h=2;h<=n;h++)
    {
        min=MAXCOST;//找到最小的,先来个较大值
        for(int j=2;j<=n;j++)
        {
            if(lowcost[j]<min&&lowcost[j]!=0)
                //如果找到权值较小的就赋值给min,并把终点j赋值给minid。
            {    min=lowcost[j]; minid=j;}
        }
        lowcost[minid]=0;//这条边已经进入最小生成树,所以把值置为0
        if(min!=MAXCPST)
        sum+=min;
        for(int s=2;s<=n;s++)
        {
            if(lowcost[s]>graph[minid][s])
//如果原先的lowcost[j]的值大于以minid为起点到终点j的权值,
//则更新它,并把起点更新为minid
            {
                lowcost[s]=graph[minid][s];
                sta[s]=minid;
            }
        }
    }
    return sum;

}
int main()
{
   int m,n,x,y,cost;
   cout<<"请输入节点数目和边的数目:"<<endl;
   cin>>m>>n;
   for(int i=1;i<=m;i++)
       for(int j=1;j<=m;j++)
           graph[i][j]=MAXCOST;

       for(int k=1;k<=n;k++)
       {
           cin>>x>>y>>cost;
           graph[x][y]=graph[y][x]=cost;
       }
      cost= Prim(graph,n);
      cout<<cost<<endl;
      return 0;
}

PRIM算法(邻接表版)

#include<bits/stdc++.h>
using namespace std;

const int maxn=1005;

struct Edge{
    int to,dist;
    Edge(int t,int d):to(t),dist(d){}
    bool operator<(const Edge& e)const{
        return dist>e.dist;
    }
};

int n,m;
bool vis[maxn];
vector<Edge> g[maxn];
priority_queue<Edge> que;

void prim(){
    memset(vis,0,sizeof(vis));
    while(que.size()) que.pop();

    for(int i=0;i<g[0].size();++i) que.push(g[0][i]);
    vis[0]=true;

    int ans=0;
    for(int cnt=1;cnt<n;++cnt){
        while(que.size() && vis[que.top().to]) que.pop();
        Edge e=que.top();
        ans+=e.dist;
        int v=e.to;
        vis[v]=true;
        for(int i=0;i<g[v].size();++i){
            if(!vis[g[v][i].to]) que.push(g[v][i]);
        }
    }
    printf("%d\n",ans);
}

int main(){
    while(scanf("%d%d",&n,&m)==2){
        for(int i=0;i<n;++i) g[i].clear();
        for(int i=0;i<m;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            g[u-1].push_back(Edge(v-1,w));
            g[v-1].push_back(Edge(u-1,w));
        }
        prim();
    }
    return 0;
}

KRUSKAL算法
(贪心+并查集)

struct edge
{
    int u,v;
    ll val;int cnt;
    bool operator< (const edge & rhs)const{return val<rhs.val;}
}E[N];
struct Kruskal
{
    int fa[N],cnt=0,n;ll ans=0;
    void add(int uu,int vv,ll vall){E[++cnt].u=uu,E[cnt].v=vv,E[cnt].val=vall;}
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void init(int nn){ for(int i=0;i<=nn;i++)fa[i]=i; n=nn;}
    void kru(){
        sort(E+1,E+1+cnt);
        int pp=0;
        for(int i=1;i<=cnt;i++){
            int u=find(E[i].u),v=find(E[i].v);
            if(u!=v){
                fa[u]=v,ans+=E[i].val;
                if(++pp>=n-1)return ;
            }
        }
    }
}kru;
#include <iostream>
#include<algorithm>
using namespace std;

#define MAX 100
struct edge
{
    int x,y;
    int w;
}e[MAX];
int fa[MAX];
int rank[MAX];
int sum;
int cmp(edge a,edge b)//排序函数
{
    if(a.w!=b.w) 
    	return a.w<b.w;
    else
        return a.x<b.x;
}
void make_set(int x)//初始化节点
{
   fa[x]=x; rank[x]=0;
}

int find(int x)//查找父节点
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}

void union_set(int x,int y,int w)//合并节点
{
     if(rank[x]>rank[y])
         fa[y]=x;
     else  if(rank[x]<rank[y])
         fa[x]=y;
     else
      rank[x]++,fa[y]=x;
     sum+=w;//总权值加上w
}
int main()
{
    int x,y,w;
    int m,n;//n是点,m是边
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        cin>>x>>y>>w;
        e[i].x=x;e[i].y=y;e[i].w=w;
        make_set(x); make_set(y);
    }
    sort(e,e+m,cmp);
    sum=0;
    for(int  i=0;i<m;i++)
    {
        x=find(e[i].x); y=find(e[i].y);
        w=e[i].w;
        if(x!=y)
            union_set(x,y,w);
    }
    cout<<sum<<endl;
    return 0;
}
内容概要:本文探讨了在MATLAB/SimuLink环境中进行三相STATCOM(静态同步补偿器)无功补偿的技术方法及其仿真过程。首先介绍了STATCOM作为无功功率补偿装置的工作原理,即通过调节交流电压的幅值和相位来实现对无功功率的有效管理。接着详细描述了在MATLAB/SimuLink平台下构建三相STATCOM仿真模型的具体步骤,包括创建新模型、添加电源和负载、搭建主电路、加入控制模块以及完成整个电路的连接。然后阐述了如何通过对STATCOM输出电压和电流的精确调控达到无功补偿的目的,并展示了具体的仿真结果分析方法,如读取仿真数据、提取关键参数、绘制无功功率变化曲线等。最后指出,这种技术可以显著提升电力系统的稳定性与电能质量,展望了STATCOM在未来的发展潜力。 适合人群:电气工程专业学生、从事电力系统相关工作的技术人员、希望深入了解无功补偿技术的研究人员。 使用场景及目标:适用于想要掌握MATLAB/SimuLink软件操作技能的人群,特别是那些专注于电力电子领域的从业者;旨在帮助他们学会建立复杂的电力系统仿真模型,以便更好地理解STATCOM的工作机制,进而优化实际项目中的无功补偿方案。 其他说明:文中提供的实例代码可以帮助读者直观地了解如何从零开始构建一个完整的三相STATCOM仿真环境,并通过图形化的方式展示无功补偿的效果,便于进一步的学习与研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值