最小生成树

最小生成树

一、Krustral 克鲁斯卡尔算法

/*
   https://vjudge.net/problem/HDU-1863
   复杂度 E*log(E) 适用于稀疏图
*/
# include <bits/stdc++.h>
using namespace std;

const int MAXN=100+100;
struct Edge
{
   int from,to,cost;
   bool operator<(const Edge &a)
  {
       return cost<a.cost;
  }
};
Edge edge[MAXN];
int father[MAXN];
void MakeSet(int n)
{
for(int i=0;i<=n;i++) father[i]=i;
return ;
}
int Find(int x)
{
   return x==father[x]?x:Find(father[x]);
}
int main()
{
   int n,m;
   while(cin>>m>>n&&m)//m代表道路数,n代表村庄数
  {
       MakeSet(n);
       for(int i=0;i<m;i++){
           Edge &t=edge[i];
           scanf("%d%d%d",&t.from,&t.to,&t.cost);
      }
       sort(edge,edge+m);
       int sum=0;
       int num=n;
       for(int i=0;i<m;i++)//一个个将边加进去
      {
           Edge t=edge[i];
           if(Find(t.from)==Find(t.to)) continue;
           father[Find(t.from)]=father[Find(t.to)];
           sum+=t.cost;
           num--;
           if(num==1) break;
      }
       if(num==1) cout<<sum<<endl;
       else cout<<"?"<<endl;
  }
return 0;
}

二、prim算法

/*
prim算法是进行加点,使用于稠密图,可以选择用堆和不用堆
不用堆 O(v*v)
用堆 O(e*log v)
*/
# include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> P;
const int MAXN=100+100;
const int INF=1e9+100;
int Away[MAXN];//记录从当前已选节点到j节点的路径的最小值
bool vis[MAXN];
int n,m;
vector<vector<P> > vec(MAXN);
void init()
{
   for(int i=0;i<=n;i++) vec[i].clear();
   memset(vis,0,sizeof(vis));
   return ;
}
int main()
{
   while(cin>>m>>n&&m) //m道路条数,n村庄个数
  {
       init();
       int from,to,w;
       while(m--){
           scanf("%d%d%d",&from,&to,&w);
           vec[from].push_back(P(w,to));
           vec[to].push_back(P(w,from));
      }//添加边
       
       for(int i=2;i<=n;i++) Away[i]=INF; //初始化Away数组
       Away[1]=0;
       int Left=n;
       int all_cost=0;
       priority_queue<P,vector<P>,greater<P> >q;//小顶堆
       q.push(P(0,1));
       
       while(!q.empty()&&Left>0)
      {
           P tmp=q.top(); q.pop();
           int To=tmp.second;
           if(vis[To]) continue; //To该点已经在最小生成树里面
           
           vis[To]=1; //加入集合
           Left--;
           all_cost+=tmp.first;
           for(int i=0;i<vec[To].size();i++)//更新Away数组
          {
               P &t=vec[To][i];
               if(!vis[t.second]&&Away[t.second]>t.first)
              {
                   Away[t.second]=t.first;
                   q.push(t);
              }
          }
      }
       
       if(Left==0) printf("%d\n",all_cost);
       else printf("?\n");
  }

   return 0;
}



posted @ 2022-02-27 14:06  fengzlj  阅读(113)  评论(0)    收藏  举报