JZOJ:【usaco2013 mar】灌溉農田(irrigation.pas/cpp/c)

本次,我主要給大家講一講有關這一題的Prim算法

首先我們來討論一下:

什麼是最小生成樹?

  1. 無迴路,且包含原圖中的n-1條邊
  2. 包含原圖中的全部頂點
  3. 邊的權重和在所有其他生成樹中最小
  4. 最小生成樹存在,則該圖一定連通。反過來一樣,圖連通,則最小生成樹一定存在

那麼如何構建滿足以上條件的生成樹?
Prim算法構建最小生成樹,
簡單來說就是在圖中,從某一頂點出發,逐步構建讓一棵小樹逐漸長大
用一個例子來說明更清晰點吧!首先看下面一張無向網圖
在這裏插入圖片描述
要構造這張圖的最小生成樹,首先,假設我們從V0頂點開始出發,
也就是以V0爲根結點開始建樹,接着往外擴展,從與V0頂點相鄰的頂點中找出權值最小的頂點,可以看到是V6,所以把V6和V0連接起來在這裏插入圖片描述
也就是把V6收錄進了這棵最小生成樹中了。
接着繼續,從當前樹中頂點的鄰接點中 (也就是V0和V6的鄰接點中,找出權值最小的頂點)。可以看到是V1,所以把V1也接入最小生成樹中。在這裏插入圖片描述
然後繼續,到V2結點,也接入最小生成樹中
在這裏插入圖片描述
因爲不能形成迴路
所以V2和V6之間不能連接(雖然權值最小,等於3)
V0和V1之間也不能連接。所以只能V6和V4連接在這裏插入圖片描述
最後V4和V5連接,V4再和V3連接,就完成了這棵最小生成樹的構建了。

本圖爲最小生成樹的最終模型在這裏插入圖片描述

好了,基本Prim算法已實現,迴歸正題

題目傳送門

首先,按照做題的方法,我們先把數據全部讀入;

然後把兩條田地修管子的費用全部求出來,注意本題是無向的;
所以way[i][j]=way[j][i];
還要注意一點,就是如果way[i][j]<c要把way[i][j]設爲達到不了 (即設成很大的數)

接着用一個p[]存儲當前點有沒有用過;

剩下的我給個關鍵代碼吧 (就是Prim算法關鍵部分)

for(int i=1;i<=n;i++) cnt[i]=way[1][i];
	for(int i=1;i<=n-1;i++)
	{
		int k=0,ji=maxn;
		for(int j=1;j<=n;j++) if(cnt[j]<ji&&!p[j]) ji=cnt[j],k=j;
		if(ji==maxn){
			printf("-1");
			return 0;
		}
		ans+=ji;
		p[k]=1;
		for(int j=1;j<=n;j++)
		if(cnt[j]>way[k][j]&&!p[j]) cnt[j]=way[k][j];
	}

最後輸出就可以了

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