nyoj-布线问题

布线问题
时间限制:1000 ms  |  内存限制:65535 KB
难度:4

描述
    南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:
    1、把所有的楼都供上电。
    2、所用电线花费最少

输入
    第一行是一个整数n表示有n组测试数据。(n<5)
    每组测试数据的第一行是两个整数v,e.
    v表示学校里楼的总个数(v<=500)
    随后的e行里,每行有三个整数a,b,c表示a与b之间如果建铺设线路花费为c(c<=100)。(哪两栋楼间如果没有指明花费,则表示这两栋楼直接连通需要费用太大或者不可能连通)
    随后的1行里,有v个整数,其中第i个数表示从第i号楼接线到外界供电设施所需要的费用。( 0<e<v*(v-1)/2 )
    (楼的编号从1开始),由于安全问题,只能选择一个楼连接到外界供电设备。
    数据保证至少存在一种方案满足要求。
输出
    每组测试数据输出一个正整数,表示铺设满足校长要求的线路的最小花费。
样例输入

    1
    4 6
    1 2 10
    2 3 10
    3 1 10
    1 4 1
    2 4 1
    3 4 1
    1 3 5 6

样例输出

    4
题目

 

这题我用prim算法和kruskal算法都提交了一下

从代码量来看,prim算法更简洁一些,从时间复杂度来看,prim:O(n^2),kruskal:O(mlogm),kruskal更优

kruskal:

#include <iostream>
#include <algorithm>
#include <cstring>
 
using namespace std;

const int Max = 2000000;

struct ed
{
       int u;
       int v;
       int w;
};
ed e[Max];

int f[Max];
int x[Max];

bool cmp(ed a,ed b)
{
    if(a.w<b.w)
     return true;
    else
      return false;
}

int getf(int v)
{
    if(f[v] == v)
      return v;
    else
    {
       f[v] = getf(f[v]);
       return f[v];
    }
}
int merge(int u,int v)
{
    int t1,t2;
    t1 = getf(f[u]);
    t2 = getf(f[v]);
    if(t1 != t2)
    {
          f[t2] = t1;
          return 1;
    }
    return 0;
}
int main()
{
    int n;
    cin >> n;
    int vn,en;
    while(n--)
    {
              int sum = 0;
              int count = 0;
              int minele;
              cin >> vn >> en;
              for(int i = 0; i < en; i++)
                cin >> e[i].u >> e[i].v >> e[i].w;
             
              for(int i = 0; i < vn; i++)
                 cin >> x[i];
              
               minele = *min_element(x,x+vn); 
              
               sort(e,e+en,cmp);       //按权值排序 
               
               for(int i = 1; i <= vn; i++)
                 f[i] = i;
               for(int i = 0; i < en; i++)
               {
                    if(merge(e[i].u,e[i].v))
                    {                       //若u和v不连通 
                         count ++;
                         sum = sum + e[i].w;
                    }
                    if(count == vn-1)
                    { 
                         break;
                    }
                }
                cout << sum + minele << endl;
       }
       return 0;
}

prim:

#include <iostream>
#include <algorithm>
#include <cstring>
 
using namespace std;
const int Max = 550;
const int inf = 999999999;
int dis[Max] ;
int e[Max][Max];
int book[Max];
int x[Max];

int main()
{
     int  n;
     int vn,en;
     cin >> n;

     while(n--)
     {
              cin >> vn >> en;
               for(int i =1;  i <= vn ;i++)
                 for(int j = 1; j <= vn ;j++)
                  e[i][j] = inf;
               memset(book,0,sizeof(book));
               int a,b,c;
               int sum = 0;
               int count = 1;
            
               for(int i = 0;i < en;i++)
               { cin >> a >> b >> c;
                 e[a][b] = c;
                 e[b][a] = c;
                 }
               for(int i = 0; i  < vn; i++)
                   cin >> x[i];
               int minele = *min_element(x,x+vn);
                 
               for(int i =1  ; i <= vn;i++)
                dis[i] = e[1][i];
                book[1] = 1;
                while(count < vn)
                {
                            int mini  = inf;
                            int j;
                            for(int i = 1; i <= vn;i ++)
                               if(book[i]==0&&dis[i] < mini)
                                  {
                                       
                                           mini = dis[i];
                                           j = i;
                                  }
                            sum = sum + dis[j];      
                            book[j] = 1;
                            count++;
                            for(int i = 1; i <= vn; i++)
                              if(dis[i] > e[j][i])  //更新顶点i到树的最短距离
                                 dis[i] = e[j][i];
                }
                       cout << sum + minele << endl;
                       }
                 return 0;
                 }          

 

转载于:https://www.cnblogs.com/ekinzhang/p/4396010.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值