CCF201412-4 最優灌溉 就是生成樹嘛~

問題描述
  雷雷承包了很多片麥田,爲了灌溉這些麥田,雷雷在第一個麥田挖了一口很深的水井,所有的麥田都從這口井來引水灌溉。
  爲了灌溉,雷雷需要建立一些水渠,以連接水井和麥田,雷雷也可以利用部分麥田作爲“中轉站”,利用水渠連接不同的麥田,這樣只要一片麥田能被灌溉,則與其連接的麥田也能被灌溉。
  現在雷雷知道哪些麥田之間可以建設水渠和建設每個水渠所需要的費用(注意不是所有麥田之間都可以建立水渠)。請問灌溉所有麥田最少需要多少費用來修建水渠。

第一眼看成了最短路,寫了半天才想起來,明明一個麥田可以連接多個麥田,這不是最小生成樹麼...

於是就選了比較簡單的Prim算法。

關於這個算法其實原理特簡單:

1、建立一個點的集合(已經經過的點)

2、更新其餘點到這個集合最近的距離

3、選擇點加入這個集合

其中更新距離的問題就是目標點到集合中所有店的距離裏的最小距離作爲其到該集合的最小距離。

把起點放到點集裏,然後不斷選擇距離最近的點加進去就好了。順便記錄一下花銷。

#include<iostream>
#include<string.h>
using namespace std;

#define MAXN 1000+5
#define INF 0x3f3f3f3f

int n,m,sum;
int map[MAXN][MAXN]; //存圖
int dis[MAXN]; // 其他點與點集的最小距離
int flag[MAXN]; // 標記點集

int solve(){
	flag[1] = 1; // 標記起點
	for (int i = 1; i <= n; i++){// 初始化起點到各邊距離
		dis[i] = map[1][i];
		map[i][i] = 0;
	}
	int min, mk;
	for (int i = 1; i<n; i++){
		min = INF; // 尋找最小值
		for (int j = 1; j <= n; j++){
			if (!flag[j] && dis[j] < min){
				min = dis[j]; mk = j;
			}
		}
		sum += min; // 記錄消費
		flag[mk]++; // 標記訪問
		for (int i = 1; i <= n; i++){ // 更新距離
			if (!flag[i] && dis[i] > map[mk][i])
				dis[i] = map[mk][i];
		}
	}
}

int main(){
	cin >> n >> m;
	memset(map, INF, sizeof(map));
	for (int i = 0; i < m; i++){
		int a, b, c;// 無向圖輸入
		cin >> a >> b >> c;
		map[a][b] = c; map[b][a] = c;
	}
	solve();
	cout << sum << endl;
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章