• 最小生成树与最小树形图


    最小生成树

    从无向图的角度讲,对于一个联通的无向图,我们可以构造出这个无向图的一棵生成树.形式化地说,一棵给定无向图$G=(V,E)$的生成树$S$是一个图$(V,E')$,满足
    1) $S$联通.
    2) $S$中不存在环.

    我们可以定义边的权值$w(E)$,一般来说,$w(E)$的值相对边是独立的(互不影响)的.一棵生成树的权值$w(T)$就是它的边的权值和.最小生成树,就是使$w(T)$最小的生成树$Tin g(G)$.$g(G)$是$G$生成树的集合.)

    最小生成树一般用著名的Kruskal算法求.这个算法很优美,写起来也很方便.

    但是这里要介绍一个不常见但是非常好用的新算法,对最小树形图的算法也很有启发.

    Borůvka 算法

    这个算法的基本思想是每次寻找可以放入最小生成树的边.算法基本步骤:

    如果没有生成最小生成树: -> 1 遍历所有边,找出点的最小外联边 -> 2 将这些外联边加入最小生成树,形成一些联通分量 -> 3 对于每个新形成的联通分量缩点

    时间复杂度分析

    每次对于一个点都会至少找出另外一个点与它组成联通块,最坏情况需要迭代$log_2{|V|}$次,每次$O(E)$,因此时间复杂度上限$O(Elog_2{V})$,对于随机图会更快些.
    这里假设并查集查找与合并的时间复杂度$O(1)$.

    最小树形图

    讲最小生成树的目的当然是为了讲最小树形图.

    对于一个有向图$G=(V,E)$,我们可以定义出它的树形图集合$g(G)$,其中的每一个元素$Sin g(G)=(V,E')$满足:
    1) $S$半联通(单向联通).
    2) $S$中没有环.

    可以看出这是一棵有根树.

    如图中的橙色边标出了这个图的一个树形图.

    补个约大爷版的代码(不是约大爷写的...对着约大爷的代码打的...)

    #include <cstdio>
    #include <algorithm>
    #include <set>
    #define fon(i,s)    for(int i=0;i<s; ++i)
    #define fone(i,s)   for(int i=0;i<=s;++i)
    #define fox(i,f,t)  for(int i=f;i<t; ++i)
    #define foxe(i,f,t) for(int i=f;i<=t;++i)
    #define fdn(i,s)    for(int i=s;i;   --i)
    #define fdne(i,s)   for(int i=s;~i;  --i)
    #define fdx(i,f,t)  for(int i=f;i>t; --i)
    #define fdxe(i,f,t) for(int i=f;i>=t;--i)
    struct Info{
    	int S,C,U;
    	Info* c[2];
    	inline Info(){}
    	inline Info(int CC){ c[0]=0,c[1]=0,S=0,U=0,C=CC; }
    	inline Info(bool ibp,Info* c0,Info* c1){
    		S=(ibp<<1)-1,c[0]=c0,c[1]=c1,U=0;
    		C=c[0]->C+S*c[1]->C;
    	}
    	inline Info* operator()(int CC){ c[0]=0,c[1]=0,S=0,U=0,C=CC;return this; }
    	inline Info* operator()(bool ibp,Info* c0,Info* c1){
    		S=(ibp<<1)-1,c[0]=c0,c[1]=c1,U=0;
    		C=c[0]->C+S*c[1]->C;
    		return this;
    	}
    	inline void pick(){++U;}
    	inline void inhr(){if(S){c[0]->U+=U,c[1]->U+=S*U,U=0;}}
    } NIL(0);
    #define VM 500001
    struct _uvec{
    	Info* a[VM];
    	int l,p;
    	inline void push_back(Info* b){a[l++]=b;}
    	inline Info* operator[](int n){return a[n];}
    	inline Info** operator+(int n){return a+n;}
    	inline int riter(){return p--;}
    	inline void startRIterSession(){p=l;}
    	inline Info* iterP(){return a[p];}
    } dr;
    Info IS[VM];
    int ISL;
    #define new_Info IS[ISL++]
    inline Info* Add(Info* a,Info* b){
    	if(a==&NIL) return b;
    	if(b==&NIL) return a;
    	Info* n=new_Info(1,a,b);
    	dr.push_back(n);
    	return n;
    }
    inline Info* Sub(Info* a,Info* b){
    	if(b==&NIL) return a;
    	Info* n=new_Info(0,a,b);
    	dr.push_back(n);
    	return n;
    }
    struct Leftist{
    	Leftist* s[2];
    	Info *vf,*Msk;
    	int vs,dist;
    	inline Leftist(Info *v=&NIL,int sx=0){ s[0]=NULL,s[1]=NULL,dist=1,vf=v,vs=sx,Msk=&NIL; }
    	inline Leftist* operator()(Info *v=&NIL,int sx=0){ s[0]=NULL,s[1]=NULL,dist=1,vf=v,vs=sx,Msk=&NIL;return this;}
    	inline int key(){
    		return vf->C;
    	}
    };
    inline int dist(Leftist* x){return (x)?x->dist:0;}
    inline void Push(Leftist* x){//Info pushdown
    	if(x->s[0]) x->s[0]->Msk=Add(x->s[0]->Msk,x->Msk);
    	if(x->s[1]) x->s[1]->Msk=Add(x->s[1]->Msk,x->Msk);
    	x->vf=Sub(x->vf,x->Msk),x->Msk=&NIL;
    }
    Leftist* Merge(Leftist* l,Leftist* r){
    	if(l==NULL) return r;
    	if(r==NULL) return l;
    	Push(l),Push(r);
    	if(l->key()>r->key()) std::swap(l,r);
    	l->s[1]=Merge(l->s[1],r);
    	if(dist(l->s[0])<dist(l->s[1])) std::swap(l->s[0],l->s[1]);
    	l->dist=dist(l->s[1])+1;
    	return l;
    }
    Leftist* Extract(Leftist* &x){
    	Push(x);Leftist* ret=x;
    	x=Merge(x->s[0],x->s[1]);
    	return ret;
    }
    #define MAXN 100012
    #define MAXM MAXN
    int N,M,hl;
    Leftist *heap[MAXN],_h[VM];
    #define _L _h[hl++]
    struct djset{
    	int f[MAXN];
    	inline void Init(){
    		int u=1+(N<<2);
    		fone(i,u) f[i<<2]=-1,f[i<<2|1]=-1,f[i<<2|2]=-1,f[i<<2|3]=-1;
    	}
    	int find(int x){return ~f[x]?(f[x]=find(f[x])):x;}
    	inline bool uni(int x,int y){
    		x=find(x),y=find(y);
    		if(x==y) return false;
    		return (f[y]=x);
    	}
    	inline bool cnx(int x,int y){
    		return find(x)==find(y);
    	}
    } weak,strong;
    std::set<int> activeStrong;//I don't want to write a set implementation T^T
    inline void Join(int u,int v){
    	strong.uni(u,v);
    	heap[u]=Merge(heap[u],heap[v]),heap[v]=NULL,activeStrong.insert(u);
    }
    Info baseInfo[MAXM],*prevCost[MAXN];
    int prev[MAXN],Ans;
    inline bool Connected(){
    	foxe(i,1,N) if(!weak.cnx(1,i)) return 0;
    	return 1;
    }
    struct _veci{
    	int s[VM],sl;
    	inline void push_back(int n){s[sl++]=n;}
    	inline void clear(){sl=0;}
    	inline int back(){return s[sl-1];}
    	inline int operator[](int n){return s[n];}
    	inline int size(){return sl;}
    } LIZ;
    int main(){
    	scanf("%d%d",&N,&M);
    	foxe(i,1,N) heap[i]=NULL;
    	foxe(i,1,M){
    		int u,v,w;scanf("%d%d%d",&u,&v,&w);
    		baseInfo[i](w);
    		if(v==1) continue;
    		heap[v]=Merge(heap[v],_L(baseInfo+i,u));
    	}
    	activeStrong.clear();
    	foxe(i,2,N) activeStrong.insert(i);
    	weak.Init(),strong.Init(),Ans=0;
    	while(activeStrong.size()){
    		int s0=*activeStrong.begin();
    		if(heap[s0]==NULL){ activeStrong.erase(s0);continue; }
    		Leftist* pdi=Extract(heap[s0]);
    		int S=strong.find(pdi->vs);
    		if(S==s0) continue;
    		if(!weak.cnx(pdi->vs,s0)){
    			prev[s0]=pdi->vs,prevCost[s0]=pdi->vf,Ans+=pdi->vf->C,pdi->vf->pick();
    			weak.uni(pdi->vs,s0);
    			activeStrong.erase(s0);
    			continue;
    		}
    		LIZ.clear();
    		LIZ.push_back(strong.find(pdi->vs));
    		while(LIZ.back()!=s0) LIZ.push_back(strong.find(LIZ.back()));
    		Ans+=pdi->vf->C;
    		pdi->vf->pick();
    		if(heap[s0]) heap[s0]->Msk=Add(heap[s0]->Msk,pdi->vf);
    		int SZ=LIZ.size();
    		fon(i,SZ-1) if(heap[LIZ[i]]) heap[LIZ[i]]->Msk=Add(heap[LIZ[i]]->Msk,prevCost[LIZ[i]]);
    		fon(i,SZ-1) Join(s0,LIZ[i]);
    	}
    	if(!Connected()){ printf("-1
    "); return 0; }
    	printf("%d
    ",Ans);
    	LIZ.clear(),dr.startRIterSession();
    	while(dr.riter()) dr.iterP()->inhr();
    	foxe(i,1,M) if((baseInfo[i].U)&&(baseInfo[i].C)) LIZ.push_back(i);
    	fon(i,Ans) printf("%d%s",LIZ[i],(i==Ans-1)?"
    ":" ");
    	return 0;
    }
  • 相关阅读:
    github单独下载一个文件夹
    搭建github服务器
    ssh xshell 连接在vim中无法用 ctrl+insert 复制黏贴
    centos 下文件夹共享
    rootkit 内核函数hook
    centos dhcp获取不到ip解决方法 Bringing up interface eth0: Device eth0 does not seem to be present,delaying initialization.
    ipc 入侵步骤
    linux 无交互添加用户设置密码
    C++笔记
    感谢路遥 感谢平凡的世界
  • 原文地址:https://www.cnblogs.com/tmzbot/p/4603215.html
Copyright © 2020-2023  润新知