最小樹形圖(朱劉演算法模板)
阿新 • • 發佈:2019-02-20
求有固定根的最小樹形圖的演算法
演算法步驟:
(1)求最短弧集:除了根節點外,找到所有其他的節點最小邊權的入邊(用in陣列記錄到達改點的最小邊權,用pre陣列記錄其父節點)
(2)檢驗生成的集合中是否存在有向圈,有的話進行步驟3,沒有進行步驟4,假如除了根節點外有的節點是孤立的,也就是沒有弧指向他,不存在最小樹形圖;
(判斷方法:利用pre陣列以每個點進行列舉搜尋)
(3)把有向環縮成一個點,形成(U1,U2,U3,U4.....Un')共n‘個點定義:不在一個環中的兩個點分別為id[u],id[v],邊權是w[u][v]-=in[v];然後進行步驟1;
(4)ans就是答案:
程式:
int mini_tree(int root,int n,int m)//分別是樹根,節點數,邊數,序號從1開始 { int ans=0; int i,u; while(1) { for(i=1;i<=n;i++) in[i]=inf; for(i=1;i<=m;i++) { int u=edge[i].u; int v=edge[i].v; if(edge[i].w<in[v]&&u!=v) { in[v]=edge[i].w; pre[v]=u; } }//找最小的入邊 for(i=1;i<=n;i++) { if(i==root)continue; ans+=in[i];//把邊權加起來 if(in[i]==inf)//如果存在沒有入弧的點則不存在最小樹形圖 return -1; } memset(id,-1,sizeof(id)); memset(use,-1,sizeof(use)); int cnt=0; for(i=1;i<=n;i++)//列舉每個點,搜尋找環 { int v=i; while(v!=root&&use[v]!=i&&id[v]==-1) { use[v]=i; v=pre[v]; } if(v!=root&&id[v]==-1)//當找到環的時候縮點編號 { ++cnt; id[v]=cnt; for(u=pre[v];u!=v;u=pre[u]) id[u]=cnt; } } if(cnt==0)//如果沒有環結束程式 break; for(i=1;i<=n;i++)//把餘下的不在環裡的點編號 if(id[i]==-1) id[i]=++cnt; for(i=1;i<=m;i++)//建立新的圖 { int u=edge[i].u; int v=edge[i].v; edge[i].u=id[u]; edge[i].v=id[v]; if(edge[i].u!=edge[i].v) edge[i].w-=in[v]; } n=cnt;//更新節點數和根節點的編號 root=id[root]; } return ans; }