图论二

0、目录

最短路、最小生成树、LCA
(参考自白皮)

1、最短路

1.1、Floyd

for(int i=1;i<=n;i++){
	for(int j=1;j<=n;j++){
		mat[i][j]=INF;
		if(i==j) mat[i][j]=0;
		pre[i][j]=i;		
	}
}

for(int k=1;k<=n;k++){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
		}
	}
}

vector<int> path;
path.push_back(t);
while(pre[s][t]!=s) {
	path.pb(pre[s][t]);
	t=pre[s][t];
}
path.push_back(s);
reverse(path.begin(),path.end());

1.2、Dijkstra

struct Edge{
	int u,v,d;
};

struct HeapNode{
	int d,u;
	HeapNode(int d,int u):d(d),u(u){}
	bool operator < (const HeapNode& tmp) const {
		return d>tmp.d;
	}
};

struct Dijkstra{
	int n,m;
	vector<Edge> egs;
	vector<int> G[maxn];
	bool done[maxn];
	int d[maxn];
	int p[maxn];
	
	void init(int n){
		this->n=n;
		for(int i=0;i<n;i++) G[i].clear();
		egs.clear(); 
	}
	
	void addEdge(int u,int v,int d){
		egs.push_back(Edge(u,v,d));
		m=egs.size();
		G[u].push_back(m-1);
	}
	
	void dijkstra(int s){
		priority_queue<HeapNode> Q;
		for(int i=0;i<n;i++) d[i]=INF;
		d[s]=0;
		memset(done,0,sizeof(done));
		Q.push(HeapNode(0,s));
		while(!Q.empty()){
			HeapNode x=Q.top(); Q.pop();
			int u=x.u;
			if(done[u]) continue;
			done[u]=1;
			for(int i=0;i<G[u].size();i++){
				Edge& e=egs[G[u][i]];
				if(d[e.v]>d[u]+e.d){
					d[e.v]=d[u]+e.d;
					p[e.v]=G[u][i];
					Q.push(HeapNode(d[e.v],e.v));
				}
			}
		}
	}
};

1.3、Spfa

struct Spfa{
	int n,m;
	vector<Edge> egs;
	vector<int> G[maxn];
	bool inq[maxn];
	int d[maxn];
	int p[maxn];
	int cnt[maxn];
	
	void init(int n){
		this->n=n;
		for(int i=0;i<n;i++) G[i].clear();
		egs.clear(); 
	}
	
	void addEdge(int u,int v,int d){
		egs.push_back(Edge(u,v,d));
		m=egs.size();
		G[u].push_back(m-1);
	}
	
	bool spfa(int s){
		queue<int> Q;
		memset(inq,0,sizeof(inq));
		memset(cnt,0,sizeof(cnt));
		for(int i=0;i<n;i++) d[i]=INF;
		d[s]=0,inq[s]=true,Q.push(s);
		while(!Q.empty()){
			int u=Q.front(); Q.pop();
			inq[u]=false;
			for(int i=0;i<G[u].size();i++){
				Edge& e=egs[G[u][i]];
				if(d[e.v]>d[u]+e.d){
					d[e.v]=d[u]+e.d;
					p[e.v]=G[u][i];
					if(!inq[e.v]){
						Q.push(e.v),inq[e.v]=true;
						if(++cnt[e.v]>n) return false;
					}
				}
			}
		}
		return true;
	}
};

2、最小生成树

2.0、两个性质

  • 切割性质:假定所有的边权均不相等。设S为既非空集也非全集的V的子集,边e是满足一个端点在S内,另一个端点不在S内的所有边中权值最小的一个,则图G的所有最小生成树均包含e。
  • 回路性质:假定所有的边权均不相同。设C是图G中的任意回路,边e是C上权值最大的边,则图G的所有最小生成树均不包含e。

2.1、无相图

/*kruskal*/
int fa[maxn];
int find(int x){ return fa[x]=fa[x]==x?x:find(fa[x]); }

int kruskal(){
	int ret=0;
	for(int i=0;i<maxn;i++) fa[i]=i;
	sort(egs,egs+m);
	for(int i=0;i<m;i++){
		Edge& e=egs[i];
		int pu=find(e.u);
		int pv=find(e.v);
		if(pu!=pv){
			fa[pv]=pu;
			ret+=e.w; 
		}
	}
	return ret;
}

2.2、有向图(最小树形图)

LL in[maxn];
int id[maxn], vis[maxn], pre[maxn];
LL Directed_MST(int rt) {
	LL ret = 0;
	while (1) {
		//求最小入度边
		for (int i = 0; i < n; i++) in[i] = INF;
		for (int i = 0; i < m; i++) {
			Edge& e = egs[i];
			if (e.w < in[e.v] && e.u != e.v) {
				in[e.v] = e.w;
				pre[e.v] = e.u;
			}
		}
		for (int i = 0; i < n; i++) {
			if (i!=rt&&in[i] == INF) return -1;
		}
		int tot = 0;
		memset(id, -1, sizeof(id));
		memset(vis, -1, sizeof(vis));
		in[rt] = 0;
		//找环,缩点
		for (int i = 0; i < n; i++) {
			ret += in[i];
			int v = i;
			while (vis[v] != i&&id[v] == -1 && v != rt) {
				vis[v] = i;
				v = pre[v];
			}
			if (id[v] == -1 && v != rt) {
				for (int u = pre[v]; u != v; u = pre[u]) {
					id[u] = tot;
				}
				id[v] = tot++;
			}
		}
		//没有环
		if (tot == 0) break;
		for (int i = 0; i < n; i++) {
			if (id[i] == -1) id[i] = tot++;
		}
		//更新到环的距离
		for (int i = 0; i < m; i++) {
			Edge& e = egs[i];
			int v = e.v;//这个v要留下来!
			e.u = id[e.u],e.v = id[e.v];
			if (e.u != e.v) {
				e.w -= in[v];
			}
		}
		n = tot;
		rt = id[rt];
	}
	return ret;
}

2.3、增量最小生成树

首先找到一颗最小生成树,之后每加一条边,在形成的环上删除权值最大的边。

2.4、次小生成树

  • 法一:删除最小生成树中的一条边,再重新跑一遍最小生成树
  • 法二:次小生成树一定可以由最小生成树加一条边再删一条边得到,因此只要枚举不在生成树上的没一条边,形成环之后删除环上的最大边就可以了。

2.5、最小瓶颈路

  • 法一:二分加bfs。
  • 法二:最小生成树上的路就是最小瓶颈路。

2.6、生成树计数问题

Matrix-tree:

//C[i][j]=无相图的度数矩阵-无相图的邻接矩阵
//Det求n-1阶主子式的行列式
LL Det(int n) {
	LL ret = 1;
	int f = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			C[i][j] = (C[i][j] % mod + mod) % mod;
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = i + 1; j <= n; j++) {
			int A = C[i][i], B = C[j][i];
			while (B != 0) {
				LL t = A / B; A = A%B; swap(A, B);
				for (int k = i; k <= n; k++) {
					C[i][k] = (C[i][k] - t*C[j][k] % mod + mod) % mod;
				}
				for (int k = i; k <= n; k++) {
					swap(C[i][k], C[j][k]);
				}
				f = -f;
			}
		}
		ret = ret*C[i][i] % mod;
	}
	if (f == -1) ret = ((-ret) % mod + mod) % mod;
	return ret;
}

3、LCA

3.1、在线倍增

//dep:深度,fa:父亲,anc:祖先
int dep[maxn];
int anc[maxn][maxm];
void dfs(int u,int f,int d) {
    dep[u]=d;
    anc[u][0]=f;
    for(int i=1; i<maxm; i++) {
        anc[u][i]=anc[anc[u][i-1]][i-1];
    }

    for(int p=head[u]; p!=-1; p=egs[p].ne) {
        Edge& e=egs[p];
        if(e.v==f) continue;
        dfs(e.v,u,d+1);
    }
}

int Lca(int u,int v) {
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=maxm-1; i>=0; i--) {
        if(dep[anc[u][i]]>=dep[v]) {
            u=anc[u][i];
        }
    }
    if(u==v) return u;
    for(int i=maxm-1; i>=0; i--) {
        if(anc[u][i]!=anc[v][i]) {
            u=anc[u][i];
            v=anc[v][i];
        }
    }
    return anc[u][0];
}

void init(){
    clr(anc[0],0);
}
posted @ 2016-07-25 00:20  fenicnn  阅读(240)  评论(0编辑  收藏  举报