下面只是講講我對次小生成樹一些理解,推薦先去看一下次小生成樹的一些概念再來看這篇部落格。
首先我們要明確一點,在最小生成樹中,任意兩個點之間有且僅有一條路徑。然後是次小生成樹由何而來,必然是最小生成樹轉變而來。如何轉變,應該是將一條不是最小生成樹中的邊,替換最小生成樹的一條邊,且替換後任意節點之間還應該有通路。那麼思路就來了。由於最小生成樹的特點,因此往樹中新增一條邊,就必然會形成乙個環,那麼去掉的邊也應該是環上屬於最小生成樹的某一條邊。大體思路就是這個樣子。
1.先形成最小生成樹,同時對於需要標記屬於最小生成樹的邊,下面**用vis來標記。
2.在每次選取乙個離生成樹最近的乙個點後,需要列舉所有已經加入最小生成樹的點,依次更新max陣列,max[i][j]表示在i節點和j節點的路徑上最小生成樹的最大權值(因為在最後列舉不是最小生成樹的邊的時候,顯然去掉環上權值最大的邊才能使次小生成樹的總值盡可能的小)。而max[i][j]的更新是dp的思想,建議好好理解。
3.最後就是列舉所有不在最小生成樹上的邊,依次更新次小生成樹。
下面的**是poj1679的題。
就是詢問所給出的資料所形成的最小生成樹是否為一。
如何判斷唯一,只需要判斷次小生成樹是否和最小生成樹相等就行了。
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
using
namespace
std;
typedef pairpii;
const
int maxn = 105;
int e[maxn][maxn];//圖
int vis[maxn][maxn];//標記邊
int dis[maxn];//原本是距離陣列,但是因為是求最小生成樹,因此也可以
int pre[maxn];//前驅節點
int max[maxn][maxn];//記錄最大權值的邊
int t, n, m;
int sum;//最小生成樹
int minsum;//次小生成樹
//bool cmp(pii a,pii b)
void prim()
for(int i = 1; i <= n; i++) else
if(dis[i] > e[i][v]) }}
}void solve() }}
if(minsum == sum) else
printf("%d\n", sum);
}int main()
prim();
solve();
}return
0;}
題目1249 次小生成樹
題目1249 次小生成樹 時間限制 1 秒 記憶體限制 32 兆 特殊判題 否 提交 140 解決 37 題目描述 最小生成樹大家都已經很了解,次小生成樹就是圖中構成的樹的權值和第二小的樹,此值也可能等於最小生成樹的權值和,你的任務就是設計乙個演算法計算圖的最小生成樹。輸入 存在多組資料,第一行乙個...
POJ 1679 次小生成樹
判斷最小生成樹是否唯一,方法是這樣的 1.對圖中每個點,掃瞄其他的邊,如果存在其他權值相同的邊,則對改邊作標記 2.然後用 kruskal或者prim 求mst 3.求的mst後,如果該mst不包含作了標記的邊,即可判定mst唯一 如果包含作了標記的邊,則依次去掉這些邊在求mst,如果求的mst權值...
POJ3255(次小生成樹)
次小生成樹裸題 到某個點的次小次短路要麼是其它某個點u的最短路加上u v的邊,要麼就是到u的次短路加上u v的邊,因此所需要求的就是到所有頂點的最短路和次短路 include include include include include using namespace std const int ...