省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可達即可)。現得到城鎮道路統計表,表中列出了任意兩城鎮間修建道路的費用,以及該道路是否已經修通的狀態。現請你編寫程序,計算出全省暢通需要的最低成本。
輸入:
測試輸入包含若干測試用例。每個測試用例的第1行給出村莊數目N ( 1< N < 100 );隨後的 N(N-1)/2 行對應村莊間道路的成本及修建狀態,每行給4個正整數,分別是兩個村莊的編號(從1編號到N),此兩村莊間道路的成本,以及修建狀態:1表示已建,0表示未建。
當N爲0時輸入結束。
輸出:
每個測試用例的輸出佔一行,輸出全省暢通需要的最低成本。
樣例輸入:
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
樣例輸出:
3
1
0
思路:如果已建成,將花費置爲0,否則爲題目給定花費。然後求最小生成樹。
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxInt = 9999;
const int MaxNum = 1000;
int c[MaxNum][MaxNum]; //鄰接矩陣
int dist[MaxNum]; //每個節點到源點的最短距離
bool visited[MaxNum]; //每個節點是否訪問過
void Prim(int s,int n)
{
for(int i = 1; i <= n; ++i)
dist[i] = c[s][i];
dist[s] = 0;
visited[s] = true;
//依次訪問接下來的n - 1個unknown節點
for(int i = 1; i <= n - 1; ++i)
{
int tmp = MaxInt; //當前最短距離
int v = s; // 當前的節點
//在所有unknown節點中找到和源點距離最短的節點
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && dist[j] < tmp)
{
v = j;
tmp = dist[j];
}
}
//找到了和源點距離最短的unknown節點,更改其訪問數組
visited[v] = true;
//然後更新其鄰接的邊,所有的邊都要訪問一次,都可能會更新
for(int j = 1; j <= n; ++j)
{
if(!visited[j] && c[v][j] < MaxInt)
{
dist[j] = min(dist[j],c[v][j]); //prim算法!!
}
}
}
}
int main()
{
int n; // n代表節點數目
while(cin >> n)
{
//跳出條件
if(n == 0)
break;
int line = n * (n - 1) / 2;
//初始化鄰接矩陣
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
c[i][j] = MaxInt;
for(int i = 0; i < line; ++i)
{
int p,q,len;
bool state;
cin >> p >> q >> len >> state;
if(len < c[p][q])//如果有重邊
{
c[p][q] = len;
c[q][p] = len; //無向圖 如果有向圖這句話就去掉
}
if(state == 1)
{
c[p][q] = 0;
c[q][p] = 0;
}
}
//初始化最短距離
for(int i = 1; i <= n; ++i)
dist[i] = MaxInt;
//初始化訪問數組
for(int i = 1; i <= n; ++i)
visited[i] = false;
Prim(1,n);
int min_dist = 0;
for(int i = 1; i <= n; ++i)
min_dist += dist[i];
cout << min_dist << endl;
}
return 0;
}