超级传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=1233
题目大意:
给出N个点之间的距离,要求建公路让N个点互相可达,求公路最短的长度。
题目分析:
由题目意思可得这一题是最小生成树的问题
下面用Prim + 优先队列 实现了一下,Prim + 优先队列 的大致想法是(我们要结合Prim来想):
Prim中有个dis[ ]的数组,点 v 到源点的距离,Prim + 优先队列 则是开一个结构体,其中两个属性 int v; //边端点 int w; //边权值 记录点 v 到源点的距离
然后用就可以优先队列在每一次循环找出 点v到源点最短的那条路径,加入最小生成树中,然后修改,把修改过的路径加入优先队列
代码实现如下:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define INFINITE 900000000
struct XEdge
{
int v; //边端点
int w; //边权值
XEdge(int v_ = 0, int w_ = INFINITE):v(v_),w(w_) { }
};
//vector<int> pt;
vector< vector<XEdge> > G(500); //图的邻接表
bool operator <(const XEdge & e1, const XEdge & e2)
{
return e1.w > e2.w;
}
int HeapPrim(const vector<vector<XEdge> > & G, int n)
//G是邻接表,n是顶点数目,返回值是最小生成树权值和
{
int i,j,k;
XEdge xDist(1,0);
priority_queue<XEdge> pq;
vector<int> vDist(n+1); //各顶点到已经建好的那部分树的距离 vector<int> vUsed(n);//标记顶点是否已经被加入最小生成树
vector<int> vUsed(n+1);//标记顶点是否已经被加入最小生成树
int nDoneNum = 0; //已经被加入最小生成树的顶点数目
for( i = 0;i <= n;i ++ ) {
vUsed[i] = 0;
vDist[i] = INFINITE;
}
nDoneNum = 0;
int nTotalW = 0;
pq.push(XEdge(1,0));
while( nDoneNum < n && !pq.empty() ) {
do {
xDist = pq.top(); pq.pop();
} while( vUsed[xDist.v] == 1 && ! pq.empty());
if( vUsed[xDist.v] == 0 ) {
nTotalW += xDist.w; vUsed[xDist.v] = 1; nDoneNum ++;
for( i = 0;i < G[xDist.v].size();i ++ ) {
int k = G[xDist.v][i].v;
if( vUsed[k] == 0) {
int w = G[xDist.v][i].w ;
if( vDist[k] > w ) {
vDist[k] = w;
pq.push(XEdge(k,w));
}
}
}
}
}
if( nDoneNum < n )
return -1; //图不连通
return nTotalW;
}
int main()
{
int N;
int temp;
int i,j;
int a,b,l;
int sum;
while(scanf("%d",&N) != EOF)
{
if(N == 0) break;
temp = N*(N-1)/2;
for(i=0;i<temp;i++)
{
scanf("%d %d %d",&a,&b,&l);
G[a].push_back(XEdge(b,l));
G[b].push_back(XEdge(a,l));
}
sum = HeapPrim(G,N);
printf("%d\n",sum);
/*for (i=0;i<500;i++)
{
G[i].clear();
}*/
G.clear();
G.resize(500);
}
return 0;
}