洛谷P1546 最短网络 Agri-Net【最小生成树

对于这道题,稍有常识的人都知道(逃是一道裸的最小生成树版题,那么就是运用到某K算法,下面简述一下。

首先定义一下生成树的概念,指的是对于一个有n个点的图,删去若干条边,使得整张图为一个只有n-1条边的联通块,而最小生成树则取生成树中的极小,既边权和为最小。

对于kruscal算法步骤如下

1.对于边的长度按照单调递增的要求排序

const int Maxn = 10010;

struct st {
   int u, v, w;
} edge[Maxn]

inline int comp (const st & a, const st & b){
     return a.w < b.w ;
}

inline void kruscal () {
   sort(edge+1, edge+1+m, comp);
   .......
}
 

 

2.贪心地从小到大选取边。对于每一个边如果连接前该边两个端点已经联通,就不选择,否则将他们联通并将该边边权计入总和,一直到加入n-1条边。

const int MAxn = 110;

int ans,fa[MAxn];

int find (int x) {

   return fa[x] == x?x:fa[x] = find(x);
   
   //路径压缩
   
}

inline void clear () {
    for (int i = 1; i < = n; ++i ) fa[i] = i;
    //初始化fa数组
    
}

inline void kruscal () {
     ......
     int cnt = 0;
     for(int i=1; i < = m; ++i){
         int uu = find (edge[i].u);
         int vv = find (edge[i].v);
         if(uu == vv) continue;
         ans += edge[i].w;
         fa[uu] = vv;
         if( ++cnt == n-1 ) break;
     }
}
 
最后输出这个总和就好了,以上就是k算法的简介。


但是这道题如果就是完全的版题,那就没有存在的意义了,首先我们注意到存边时我们对于无向图只存边一次,如果将整个矩阵存图,那么无疑会导致错误,通过观察易得,对于右上角的矩阵来说,y都大于x,易得存图代码。

int m = 0, val;

inline void add_edge ( int u, int v, int w ) {
      edge[++m].u = u;
      edge[m].v = v;
      edge[m].w = w;
}

int main(){
  scanf ( "%d", &n );
  for ( int i = 1; i <= n; ++i )
    for ( int j = 1; j <= n; ++j ) {
         scanf ( "%d", &val ) ;
         if ( j < i ) add_edge ( i, j, val ) ;
        }



最后附上本题完整ac代码以及ac用时

#include<bits/stdc++.h>
using namespace std;
const int Maxn=110;
const int MAxn=10010;
int n,val,cnt=0;
int tot=0,ans=0,fa[Maxn];
struct st{
    int u,v,w;
}edge[MAxn];
inline void add_edge(int u,int v,int w){
    edge[++cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
}
int comp(const st &a,const st &b){
    return a.w<b.w;
}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void kruscal(){
    sort(edge+1,edge+1+cnt,comp);
    for(int i=1;i<=cnt;++i){
        int uu=find(edge[i].u);
        int vv=find(edge[i].v);
        if(uu==vv) continue;
        ans+=edge[i].w;
        fa[uu]=vv;
        if(++tot==n-1) break;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=n;++i)
      for(int j=1;j<=n;++j){
          scanf("%d",&val);
          if(j>i) add_edge(i,j,val);
    }
    kruscal();
    printf("%d",ans);
    return 0;
} 

 



不要介意码分的转化,博主现在在变码分,见谅

最后,希望大家指出我博客错误,OI就是一个共同学习的过程


posted @ 2018-09-26 00:15  Hadesa  阅读(102)  评论(0编辑  收藏  举报