最小生成樹與次小生成樹
我們都知道要求最小生成樹有兩種方法可求,分別是prim演算法和kruskal演算法
1.prim演算法
設圖g =(v,e),其生成樹的頂點集合為u。
①、把v0放入u。
②、在所有u∈u,v∈v-u的邊(u,v)∈e中找一條最小權值的邊,加入生成樹。
③、把②找到的邊的v加入u集合。如果u集合已有n個元素,則結束,否則繼續執行②。
2.kruskal演算法
首先將所有邊按邊權排序,然後按照邊權從小到大依次處理.這裡要用到並查集的思想,假設已有點集u,現在正在處理邊i->j,如果i,j已在
u中則處理下一條邊,否則將i,j加入並查集中.繼續處理下一條邊,直到有n-1條邊為止.
3 次小生成樹
次小生成樹可由最小生成樹換一條邊得到
演算法:1)先用prim求出最小生成樹t,在prim的同時,用乙個矩陣max[u][v]記錄在樹中連線u-v的路徑中權值最大的邊.
2)列舉所有不在t中的邊u-v,加入邊u-v,刪除權值為max[u][v]的邊,不斷列舉找到次小生成樹.
下面給出次小生成樹的模板
#include#include#includeusing namespace std;
const int inf=0x3f3f3f3f;
int g[110][110],dist[110],mmax[110][110]; ///g儲存地圖 dist儲存從起點到其餘各點的距離 maxn儲存從i到j的最大邊權值
int pre[110]; ///pre儲存j的離它最近的是哪個點
bool mark[110]; ///相當於vis 用來標記該點是否已經用過
bool connect[110][110]; ///儲存i-j的那條邊是否加入了最小生成樹 false 加入 true 沒有
int mst,mint; ///mst儲存最小生成樹的權值和
int n,m;
int prim()
dist[1]=0;
mark[1]=true;
for(i=1;immax[j][fa])?mmax[fa][p]:mmax[j][fa];
for(j=1;j<=n;j++)}}
return res;
}int main()
mst=prim();
int i,j;
bool flag=false;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
}if(flag)
printf("not unique!\n");
else
printf("%d\n",mst);
}return 0;
}
下面來一道題練練手
題意:題目大意:
有n個城市,秦始皇要修用n-1條路把它們連起來,要求從任一點出發,都可以到達其它的任意點。秦始皇希望這所有n-1條路長度之和最短。然後徐福突然有冒出來,說是他有魔法,可以不用人力、財力就變出其中任意一條路出來。
秦始皇希望徐福能把要修的n-1條路中最長的那條變出來,但是徐福希望能把要求的人力數量最多的那條變出來。對於每條路所需要的人力,是指這條路連線的兩個城市的人數之和。
最終,秦始皇給出了乙個公式,a/b,a是指要徐福用魔法變出的那條路所需人力, b是指除了徐福變出來的那條之外的所有n-2條路徑長度之和,選使得a/b值最大的那條。
分析與總結
為了使的a/b值最大,首先是需要是b盡量要小,所以可先求出n個城市的最小生成樹。然後,就是決定要選擇那一條用徐福的魔法來變。
因此,可以列舉每一條邊,假設最小生成樹的值是minmst, 而列舉的那條邊長度是w[i][j], 如果這一條邊已經是屬於最小生成樹上的,那麼最終式子的值是a/(minmst-w[i][j])。如果這一條不屬於最小生成樹上的, 那麼新增上這條邊,就會有n條邊,那麼就會使得有了乙個環,為了使得它還是乙個生成樹,就要刪掉環上的一棵樹。 為了讓生成樹盡量少,那麼就要刪掉除了加入的那條邊以外,權值最大的那條路徑。 假設刪除的那個邊的權值是path[i][j], 那麼就是a/(minmst-path[i][j]).
解這題的關鍵也在於怎樣求出次小生成樹。
ac**:
#include #include #include #include #include #define inf 0x3f3f3f3f
#define max 1010
using namespace std;
double map[max][max], dis[max], maxn[max][max]; ///map陣列儲存地圖 dis儲存從起點到其他點的距離 maxn儲存i到j的最大權值
int pre[max], vis[max];
bool used[max][max];
int n;
struct edge
edge[max];
double cal(edge a, edge b)
double prim()
vis[1] = 1;
int k;
for(int i = 1; i < n; i++)
}if(minn == inf) return -1;
vis[k] = 1;
ret+=minn;
father = pre[k];
used[father][k] = used[k][father] = 1;
maxn[father][k] = minn;
for(int j = 1; j <= n; j++)
for(int j = 1; j <= n; j++)}}
return ret;
}int main()
map[i][i] = 0;
}for(int i = 1; i <= n; i++)
for(int i = 1; i <= n; i++)
}double ans = prim();
double ans1 = -1;
for(int i = 1; i<= n; i++)}}
printf("%.2lf\n",ans1);
}return 0;
}
最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...
次小生成樹
演算法引入 設g v,e,w 是連通的無向圖,t是圖g的一棵最小生成樹 如果有另一棵樹t1,滿足不存在樹t t t1 則稱t1是圖g的次小生成樹 演算法思想 鄰集的概念 由t進行一次可行交換得到的新的生成樹所組成的集合,稱為樹t的鄰集,記為n t 設t是圖g的最小生成樹,如果t1滿足 t1 min,...
次小生成樹
分類 圖論 2013 02 12 15 03 32人閱讀收藏 舉報次小生成樹 在求最小生成樹時,用陣列path i j 來表示mst中i到j最大邊權。求完後,直接列舉所有不在mst中的邊,把它加入到mst中構成一棵新的樹,且該樹有環,此環是由剛加入的邊 i,j 造成的,所以可以通過刪除path i ...