版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wingrez/article/details/89632273
布线问题
来源:NYOJ
标签:最小生成树
参考资料:
相似题目:
题目
南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:
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算法求最小生成树。
参考代码
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAXN 505 //顶点的最大个数
using namespace std;
struct Edge{
int v; //顶点
int u; //下一个顶点
int w; //权值
Edge(int v,int u,int w):v(v),u(u),w(w){}
bool operator < (const Edge &e) const {
return w>e.w;
}
};
vector<Edge> adj[MAXN]; //agj[v]:与v相连的边
vector<Edge> mst; //最小生成树
priority_queue<Edge> pq; //优先队列,存放横切边
int vis[MAXN]; //访问标志
void Prim(); //Prim算法,计算最小生成树
void visit(int v); //设置访问标志,并将与v相邻结点(未被访问)的边加入优先队列中
void Prim(){
visit(1);
while(!pq.empty()){
Edge e=pq.top();
pq.pop();
if(vis[e.v] && vis[e.u]) continue;
mst.push_back(e);
if(!vis[e.v]) visit(e.v);
if(!vis[e.u]) visit(e.u);
}
}
void visit(int v){
vis[v]=1;
for(vector<Edge>::iterator i=adj[v].begin(); i!=adj[v].end();i++){
if(!vis[(*i).u]){
pq.push(*i);
}
}
}
int N;
int n,m;
int v,u,w;
int main(){
scanf("%d",&N);
while(N--){
memset(vis,0,sizeof(vis));
mst.clear();
for(int i=0;i<MAXN;i++) adj[i].clear();
while(!pq.empty()) pq.pop();
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d%d",&v,&u,&w);
adj[v].push_back(Edge(v,u,w));
adj[u].push_back(Edge(u,v,w));
}
int mn=100; //外界供电设备到学校的最短距离
for(int i=1;i<=n;i++){
scanf("%d",&w);
if(mn>w) mn=w;
}
Prim();
int ans=0;
for(vector<Edge>::iterator i=mst.begin();i!=mst.end();i++){
ans+=(*i).w;
}
printf("%d\n",ans+mn);
}
return 0;
}