1. 程式人生 > >最小樹形圖(劉朱演算法)記錄

最小樹形圖(劉朱演算法)記錄

演算法步驟:

1、建立最短邊集(有向邊), 注意除去自環(自己連向自己)
in[v] 記錄最小權值,pre[v] 記錄邊的起點
例子:
邊1 A->B 權:5
邊2 C->B 權:3

則 in[B]=3 pre[B]=C

若集合建立完畢後,仍有孤立的點,則不存在最小樹形圖。

2、查詢有向環,並把它縮成一個點
方法: 設定環中點的編號 id[x]=newnode;

3、若沒有 有向環則已經構建最小樹形圖 ,輸出結果

否則,把剩餘不在環中的點收集起來。
再更新邊
int v=Edge.to;
Edge.from=id[Edge.from]
Edge.to=id[Edge.to]
重要:


如果不構成自環,即Edge.from!=Edge.to
則 Edge.cost-=in[v]

模板:

// 假設點集1-n  邊集0- m-1  起點是1
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn=200;
const int maxm=1e4+10;
const int INF=0x3f3f3f3f;

struct Edge
{
    int from,to,cost;
    Edge() {}
    Edge(int
f,int t,int c):from(f),to(t),cost(c) {} }edges[maxm]; int pre[maxn]; int n,m; int in[maxn],id[maxn],vis[maxn]; //vis記錄環 void init() //建圖 { scanf("%d%d",&n,&m); int cnt=0; for (int i=0;i<m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); if (u!=v) edges[cnt++]=Edge(u,v,c); //除去自環
} m=cnt; } int work(int s) //最小樹形圖演算法 { int ret=0; while(1) { for (int i=1;i<=n;i++) in[i]=INF; //建立最短邊集 for (int i=0;i<m;i++) { Edge e=edges[i]; if (e.to!=e.from && in[e.to]>e.cost) { //易錯!! e.to!=e.from 自環 pre[e.to]=e.from; in[e.to]=e.cost; } } for (int i=1;i<=n;i++) { if (i!=s&&in[i]==INF) return -1; //存在孤立點 不存在最小樹形圖 } int np=in[s]=0; memset(vis,-1,sizeof(vis)); memset(id,-1,sizeof(id)); for (int i=1;i<=n;i++) { ret+=in[i]; int v=i; while (vis[v]!=i&&id[v]==-1&&v!=s) { //不找到環 不存在其他環中 不是根 vis[v]=i; v=pre[v]; } if (id[v]==-1&&v!=s) { //找到有向環(因第一個條件而跳出while, 即滿足後兩個條件 ) np++; for (int u=pre[v];u!=v;u=pre[u]) { id[u]=np; } id[v]=np; } } if (np==0) break; for (int i=1;i<=n;i++) //收集非環點 if (id[i]==-1) id[i]=++np; for (int i=0;i<m;i++) { //重新處理邊 int u=edges[i].from; int v=edges[i].to; edges[i].from=id[edges[i].from]; edges[i].to=id[edges[i].to]; if (edges[i].from!=edges[i].to) { edges[i].cost-=in[v]; } } n=np; s=id[s]; //新點數,新起點 } return ret; } int main() { init(); int ans=work(1); if (~ans) printf("%d\n",ans); else printf("impossible\n"); return 0; }

相關推薦

樹形圖演算法記錄

演算法步驟: 1、建立最短邊集(有向邊), 注意除去自環(自己連向自己) in[v] 記錄最小權值,pre[v] 記錄邊的起點 例子: 邊1 A->B 權:5 邊2 C->B 權:3 則 in[B]=3 pre[B]=C

POJ 3164 樹形圖 演算法

Command Network Time Limit: 1000MS Memory Limit: 131072K Total Submissions: 20151 Accepted: 5792 Description After a l

樹形圖演算法模板

求有固定根的最小樹形圖的演算法 演算法步驟: (1)求最短弧集:除了根節點外,找到所有其他的節點最小邊權的入邊(用in陣列記錄到達改點的最小邊權,用pre陣列記錄其父節點) (2)檢驗生成的集合中是否

POJ 3164 Command Network樹形圖模板題+詳解

noop clu html 建立 eof std const temp pri http://poj.org/problem?id=3164 題意: 求最小樹形圖。 思路: 套模板。 引用一下來自大神博客的講解:http://www.cnblogs.co

有向圖小生成樹——樹形圖

對於有向圖的最小生成樹 , 也叫做最小樹形圖 。 最小樹形圖的第一個演算法是1965年朱永津和劉振巨集提出的複雜度為O(VE)的演算法。 值得我們驕傲啊 。 下面來分享這個演算法 。 1、求最小樹形圖之前一定要確定根 , 確定根之後再去驗證是否存在樹形圖(這個很簡單 , 就是從根節點能不能到其他點)

POJ 2195 Going Home權匹配、KM演算法

題目連結: POJ 2195 Going Home 題意: 給出一個r*c的矩陣,字母H代表房屋,字母m代表客人,房屋的數量和客人的數量相同。每間房只能住一個人。求這些客人全部住進客房的最少移動步數? #include <cstdio>

旋轉陣列的數字無重複數字

class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { if(rotateArray.size()==1) {

AOJ2249 短路+花費雙權值

擴展 最小 col 滿足 fill 最短 題解 return queue 寫題解之前先罵一下這道題 xxx給數據範圍點數<1e4,邊數<2e4,結果我開2e4和3e4都RE,然後找問題一個多小時,最後我開了1e5和2e5,題面太能唬人了吧!?真是sb題面 ---

BZOJ1797: [Ahoi2009]Mincut 洛谷P4126

最小割 Tarjan 結論題。。。 跑一遍最小割,對殘量網路進行縮點,使得剩下的邊都是滿流邊。 一條邊屬於最小割的並集當這條邊兩個端點所在的聯通塊不同。 一條邊屬於最小割的交集當這條邊兩個端點所在的聯通塊分別與源點和匯點相同。 下面給出口胡: 如果這條邊的兩個

JS 求一組陣列中的大值,不包括0

<body> <script type="text/javascript"> var arr=[]; do{ var num=prompt("請輸入一個整數:") if(num!=0){

隨筆-尋找旋轉排序陣列中的有重複元素

題目: 假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。 ( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。 請找出其中最小的元素。 注意陣列中可能存在重複的元素。 示例 1: 輸入: [1,3,5] 輸出: 1

隨筆-尋找旋轉排序陣列中的無重複數字

題目: 假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。 ( 例如,陣列 [0,1,2,4,5,6,7] 可能變為 [4,5,6,7,0,1,2] )。 請找出其中最小的元素。 你可以假設陣列中不存在重複元素。 示例 1: 輸入: [3,4,5,1,2] 輸

vc編譯exe的體積優化附編譯器引數

人們都說vc做出的東西可以小點,現在你開啟vc編譯一個Hello World出來!點屬性看下,咦!我沒走眼吧,就一Hello World就160kb真是要人命啊!  呵呵!上面的情況是筆者所遭遇的情況.不過後來了解vc可以通過設定引數來自定義編譯方式.為什麼檔案那麼大!主要是編譯器加入了很多沒必要的程式碼

面試題8:旋轉陣列的Leetcode-153,154

題目:把一個數組最開始的若干元素搬到陣列的末尾,稱為陣列的旋轉。 輸入一個遞增陣列的一個旋轉,輸出其最小值。假設這個遞增陣列中沒有重複元素 例如陣列{3,4,5,1,2}是{1,2,3,4,5}的一個旋轉,最小值是1。 一. O(N)解法 最直觀的解

旋轉陣列的數字改造二分法

題目:把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入一個遞增排序的陣列的一個旋轉,輸出旋轉陣列的最小元素。例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。 思路:這兒題目說了陣列是有序的,為了提升效率,可以用二分查詢去做,題目上也說了用二分查詢去

練習4-10 找出20 point(s)

練習4-10 找出最小值 (20 point(s)) 本題要求編寫程式,找出給定一系列整數中的最小值。 輸入格式: 輸入在一行中首先給出一個正整數n,之後是n個整數,其間以空格分隔。 輸出格式: 在一行中按照“min = 最小值”的格式輸出n個整數中的最小值。 輸入樣例:

LeetCode -- Triangle 路徑求 動態規劃問題

Given a triangle, find the minimum path sum from top to bottom.  Each step you may move to adjacent numbers on the row below. For example, given the foll

計算跨度阿里筆試題

題目:給定兩個由數字0-9組成的字元陣列,如“2345”, “4436”,從這兩個陣列分別取數,生成新陣列。比如生成:44234365,生成方式如下圖所示,每個陣列取數放入新陣列的時候,是按照下標從小到大取得。對於字元陣列,定義跨度值:K(c),為數字c最大下標和最小下標之差

資料結構與算法系列----多源短路徑Floyd-Warshall演算法

任意兩點最短路徑被稱為多源最短路徑,即給定任意兩個點,一個出發點,一個到達點,求這兩個點的之間的最短路徑,就是任意兩點最短路徑問題,多源最短路徑,而Floyd-Warshall演算法最簡單,只有5行程式碼,即可解決這個問題。 上圖中有4個城市8條公路,公路上的數字表示這條

圖論大流Edmond Karp演算法

Edmond Karp演算法的大概思想: 反覆尋找源點s到匯點t之間的增廣路徑,若有,找出增廣路徑上每一段[容量-流量]的最小值delta,若無,則結束。 在尋找增廣路徑時,可以用BFS來找,並且更新殘留網路的值(涉及到反向邊)。 而找到delta後,則使最