图论 —— 生成树 —— 最小树形图
生活随笔
收集整理的這篇文章主要介紹了
图论 —— 生成树 —— 最小树形图
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
【概述】
最小樹形圖,就是給出一個帶權有向圖,從中指定一個特殊的結點 root,求一棵以 root 為根的有向生成樹 T,且使得 T 中所有邊權值最小。
簡單來說,最小樹形圖就是有向圖的最小生成樹。
【朱劉算法】
1.過程
簡單來說,朱劉算法分為四個過程:
1)求最短弧集合 E
2)判斷集合 E 中有沒有有向環,如果有轉步驟 3,否則轉 4
3)收縮點,把有向環收縮成一個點,并且對圖重新構建,包括邊權值的改變和點的處理,之后再轉步驟 1
4)展開收縮點,求得最小樹形圖
2.實現
struct Edge{int x,y;int w; }edge[N]; int vis[N]; int id[N];//結點所屬環編號 int in[N],pre[N];//in[]為最小入邊權,pre[]為其對應的起點 int zhuLiu(int root,int n,int m){//root結點、點數、邊數int res=0;//最小樹形圖總權值while(true){for(int i=0;i<n;i++)//初始化為無窮大in[i]=INF;//尋找每個點的最小入邊for(int i=0;i<m;i++){//遍歷每條邊int x=edge[i].x;int y=edge[i].y;if(edge[i].w<in[y] && x!=y){//更新最小入邊pre[y]=x;//記錄前驅in[y]=edge[i].w;//更新}}//判斷是否存在最小樹形圖for(int i=0;i<n;i++){if(i==root)continue;if(in[i]==INF)//除根節點外的點存在孤立點return -1;}//尋找所有的環int cnt=0;//記錄環數in[root]=0;memset(id,-1,sizeof(id));memset(vis,-1,sizeof(vis));for(int i=0;i<n;i++){//標記每個環res+=in[i];//記錄權值int y=i;while(vis[y]!=i&&id[y]==-1&&y!=root){//尋找圖中有向環//三種情況會終止:找到出現同樣標記的點、結點已屬其他環、遍歷到根vis[y]=i;//標記y=pre[y];//向上找}if(y!=root&&id[y]==-1){//沒有遍歷到根或沒有找到結點屬于其他環,說明找到有向環for(int x=pre[y];x!=y;x=pre[x])//標記結點x為第幾個環id[x]=cnt;//記錄結點所屬環號id[y]=cnt++;//記錄結點所屬環號并累加}}if(cnt==0)//無環break;for(int i=0;i<n;i++)//可能存在獨立點if(id[i]==-1)//環數累加id[i]=cnt++;//建立新圖,縮點重新標記for(int i=0;i<m;i++){int x=edge[i].x;int y=edge[i].y;edge[i].x=id[x];edge[i].y=id[y];if(id[x]!=id[y])//兩點不在同一環內,更新邊權值edge[i].w-=in[y];//x到y的距離為邊權-in[y]}n=cnt;//以環數為下次操作的點數,繼續上述操作,直到無環root=id[root];}return res; } int main(){int n,m;//n個點m條有向邊scanf("%d%d",&n,&m);for(int i=0;i<m;i++){//建圖scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].w);if(edge[i].x==edge[i].y)//除去自環,即點到自身距離為INFedge[i].w=INF;}int res=zhuLiu(0,n,m);if(res==-1)printf("No\n");elseprintf("%d\n",res);return 0; }?
總結
以上是生活随笔為你收集整理的图论 —— 生成树 —— 最小树形图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 单词接龙(洛谷-P1019)
- 下一篇: 红与黑(信息学奥赛一本通-T1216)