題目鏈接:HDU 1102 Constructing Roads
Constructing Roads
We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.
Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
#define maxn 110
#define INF 0xffff
int g[maxn][maxn];
int n;
struct node
{
int v, key;
friend bool operator<(node a, node b)
{
return a.key > b.key;
}
};
bool visited[maxn];
node vx[maxn];
priority_queue<node> q;
void Prim()
{
for(int i = 1; i <= n; i++)
{
vx[i].v = i;
vx[i].key = INF;
visited[i] = false;
}
vx[1].key = 0;
q.push(vx[1]);
while(!q.empty())
{
node nd = q.top();
q.pop();
int st = nd.v;
if(visited[st])
continue;
visited[st] = true;
for(int j = 1; j <= n; j++)
{
if(j != st && !visited[j] && vx[j].key > g[st][j])
{
vx[j].key = g[st][j];
q.push(vx[j]);
}
}
}
}
int main()
{
int m, a, b;
while(~scanf("%d", &n))
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
scanf("%d", &g[i][j]);
g[i][i] = INF;
}
scanf("%d", &m);
while(m--)
{
scanf("%d%d", &a, &b);
g[a][b] = g[b][a] = 0;
}
Prim();
int ans = 0;
for(int i = 1; i <= n; i++)
ans += vx[i].key;
printf("%d\n", ans);
}
return 0;
}
鄰接表:
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
#define maxn 110 //最大頂點個數
int n, m; //頂點數,邊數
struct arcnode //邊結點
{
int vertex; //與表頭結點相鄰的頂點編號
int weight; //連接兩頂點的邊的權值
arcnode * next; //指向下一相鄰接點
arcnode() {}
arcnode(int v,int w):vertex(v),weight(w),next(NULL) {}
};
struct vernode //頂點結點,爲每一條鄰接表的表頭結點
{
int vex; //當前定點編號
arcnode * firarc; //與該頂點相連的第一個頂點組成的邊
}Ver[maxn];
void Init() //建立圖的鄰接表需要先初始化,建立頂點結點
{
for(int i = 1; i <= n; i++)
{
Ver[i].vex = i;
Ver[i].firarc = NULL;
}
}
void Insert(int a, int b, int w) //尾插法,插入以a爲起點,b爲終點,權爲w的邊,效率不如頭插,但是可以去重邊
{
arcnode * q = new arcnode(b, w);
if(Ver[a].firarc == NULL)
Ver[a].firarc = q;
else
{
arcnode * p = Ver[a].firarc;
if(p->vertex == b)
{
if(p->weight > w)
p->weight = w;
return ;
}
while(p->next != NULL)
{
if(p->next->vertex == b)
{
if(p->next->weight > w);
p->next->weight = w;
return ;
}
p = p->next;
}
p->next = q;
}
}
void Insert2(int a, int b, int w) //頭插法,效率更高,但不能去重邊
{
arcnode * q = new arcnode(b, w);
if(Ver[a].firarc == NULL)
Ver[a].firarc = q;
else
{
arcnode * p = Ver[a].firarc;
q->next = p;
Ver[a].firarc = q;
}
}
struct node //保存key值的結點
{
int v;
int key;
friend bool operator<(node a, node b) //自定義優先級,key小的優先
{
return a.key > b.key;
}
};
#define INF 0xfffff //權值上限
bool visited[maxn]; //是否已經加入樹
node vx[maxn]; //保存每個結點與其父節點連接邊的權值
priority_queue<node> q; //優先隊列stl實現
void Prim() //s表示根結點
{
for(int i = 1; i <= n; i++) //初始化
{
vx[i].v = i;
vx[i].key = INF;
visited[i] = false;
}
vx[1].key = 0;
q.push(vx[1]);
while(!q.empty())
{
node nd = q.top(); //取隊首,記得趕緊pop掉
q.pop();
if(visited[nd.v]) //注意這一句的深意,避免很多不必要的操作
continue;
visited[nd.v] = true;
arcnode * p = Ver[nd.v].firarc;
while(p != NULL) //找到所有相鄰結點,若未訪問,則入隊列
{
if(!visited[p->vertex] && p->weight < vx[p->vertex].key)
{
vx[p->vertex].key = p->weight;
vx[p->vertex].v = p->vertex;
q.push(vx[p->vertex]);
}
p = p->next;
}
}
}
int main()
{
int m, a, b, x;
while(~scanf("%d", &n))
{
Init();
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
scanf("%d", &x);
if(x != 0)
Insert2(i, j, x);
}
}
scanf("%d", &m);
while(m--)
{
scanf("%d%d", &a, &b);
Insert(a, b, 0);
Insert(b, a, 0);
}
Prim();
int ans = 0;
for(int i = 1; i <= n; i++)
ans += vx[i].key;
printf("%d\n", ans);
}
return 0;
}