C++学习笔记:图论——缩点详解

news/2024/7/15 18:53:12 标签: 图论, 缩点, Tarjan

引言

缩点,哲学的东西,你必须拥有。。。


缩点

个人认为就是把一堆强连通的点( 即强连通分量 ),认作为一个点

强连通分量就是这里面的点可以相互到达(算是个环)

 


详解

一个有向图如下

可以看出有强连通分量 { 1 , 2 } , { 8 , 4 , 9  } , { 7 } , { 6 } , { 3 } , { 5 }

先走一波Tarjan,求出强连通分量

用一个 cnt 记录一下强连通分量的和

然后在Trjan中记录每个点所属强连通分量,以及一些sao操作

void Tarjan( int x ) {//求强连通分量,缩点 
    num ++ ;
	DFN[x] = low[x] = num ;
	S.push(x);
	inS[x] = 1 ;
	for(int i = 0 ; i < G[x].size() ; ++ i ) {
		int s = G[x][i] ;
		if( !DFN[s] ) {
			Tarjan( s );
			low[x] = min( low[x] , low[s] );
		}
		else if( inS[s] )
			low[x] = min( low[x] , DFN[s] );
	}
	if( low[x] == DFN[x] ) {
        cnt ++ ;
        int now ;
        do{
            now = S.top() ;
            S.pop();
            d[now] = cnt ;
            inS[now] = 0 ;
            if( now == sta )//记录缩点后的起始点 
            	be = cnt ;
            W[cnt] += w[now] ;
        }while( now != x );
    }
}

然后就是连接缩点后的图

先记录一下每条边

for( int i = 1 ; i <= m ; ++ i ) {
		int a , b ;
		scanf("%d%d", &a , &b );
		G[a].push_back(b);
		way[i].from = a , way[i].to = b ;
	}

然后就是关键,一波sao操作

如果原图一条边上两点属于不同的强连通分量,则两个强连通分量相连,就可以对这两个分量连接

for( int i = 1 ; i <= m ; ++ i ) {//连接缩点后的图 
		int a = d[way[i].from] ;
		int b = d[way[i].to] ;
		if( a != b )//不属于同一分量
			g[a].push_back(b); 
	}

然后可以得到缩点后的图,就可以为所欲为了...嘿嘿嘿......嘿


模板

又多一个板子背。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#define ll long long
#define MAXN 500005
using namespace std ;
 
vector <int> G[MAXN] ;//初始图 
vector <int> g[MAXN] ;//缩点后的图 
stack <int> S ; 
int m , n , ans ;
int sta ;
int w[MAXN] , d[MAXN] ;//w点权,d表示该点所属分量 
bool inS[MAXN] ;//inS是否在栈中 ,vis在SPFA ,inQ是否在队列 
int DFN[MAXN] , low[MAXN] ;//Tarjan用 
int cnt , W[MAXN] , num , be , fsum , f[MAXN] ;//缩点信息 
 
struct node{
	int from , to ;
}way[MAXN];
 
void Tarjan( int x ) {//求强连通分量,缩点 
    num ++ ;
	DFN[x] = low[x] = num ;
	S.push(x);
	inS[x] = 1 ;
	for(int i = 0 ; i < G[x].size() ; ++ i ) {
		int s = G[x][i] ;
		if( !DFN[s] ) {
			Tarjan( s );
			low[x] = min( low[x] , low[s] );
		}
		else if( inS[s] )
			low[x] = min( low[x] , DFN[s] );
	}
	if( low[x] == DFN[x] ) {
        cnt ++ ;
        int now ;
        do{
            now = S.top() ;
            S.pop();
            d[now] = cnt ;
            inS[now] = 0 ;
            if( now == sta )
            	be = cnt ;
            W[cnt] += w[now] ;
        }while( now != x );
    }
}

int main() {
	scanf("%d%d", &n , &m );//基本输入 
	for( int i = 1 ; i <= m ; ++ i ) {
		int a , b ;
		scanf("%d%d", &a , &b );
		G[a].push_back(b);
		way[i].from = a , way[i].to = b ;
	}
	for( int i = 1 ; i <= n ; ++ i )
		scanf("%d", &w[i] );
	scanf("%d%d", &sta );
	for( int i = 1 ; i <= n ; ++ i ) {//缩点 
        num = 0 ;
		if( !DFN[i] )
			Tarjan( i );
	}
	for( int i = 1 ; i <= m ; ++ i ) {//连接缩点后的图 
		int a = d[way[i].from] ;
		int b = d[way[i].to] ;
		if( a != b )
			g[a].push_back(b); 
	}
}

 


http://www.niftyadmin.cn/n/943156.html

相关文章

C++解题报告:病毒(virus)——拓扑排序

题目描述 有一天&#xff0c;小y突然发现自己的计算机感染了一种病毒&#xff01;还好&#xff0c;小y发现这种病毒很弱&#xff0c;只是会把文档中的所有字母替换成其它字母&#xff0c;但并不改变顺序&#xff0c;也不会增加和删除字母。 现在怎么恢复原来的文档呢&#xf…

bzoj 2186: [Sdoi2008]沙拉公主的困惑

Description 大富翁国因为通货膨胀&#xff0c;以及假钞泛滥&#xff0c;政府决定推出一项新的政策&#xff1a;现有钞票编号范围为1到N的阶乘&#xff0c;但是&#xff0c;政府只发行编号与M!互质的钞票。房地产第一大户沙拉公主决定预测一下大富翁国现在所有真钞票的数量。现…

浅论 欧拉路径欧拉回路

欧拉路径 废话不扯&#xff0c;直接先了解一下定义 如果图G中的一个路径包括每个边恰好一次&#xff0c;则该路径称为欧拉路径(Euler path) 这需要跟哈密顿路区别一下&#xff0c;前者是边&#xff0c;后者是点 如果一个图中存在具有欧拉路径但不具有欧拉回路则称为半欧拉图 …

HDU1879,继续畅通工程(Kruskal算法)

用最小生成树中的Kruskal算法解决。 代码如下&#xff1a; #include<cstdio> #include<algorithm> #include<iostream> using namespace std; const int maxn1e45; struct E {int f,t;int wei; }edge[maxn]; int fa[105];bool cmp(E x, E y) {return x.wei…

HDU1301, Jungle Roads(Kruskal算法)

用最小生成树中的Kruskal算法解决。在这里插入代码片 代码如下&#xff1a; #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn1e35; int fa[27]; struct eg {int f,t;int wei; }edge…

C++解题报告——Rima(字典树+树形DP)

题目描述 Adrian对单词押韵很感兴趣。如果两个单词的最长公共后缀的长度与两个单词中较长那个的长度一样&#xff0c;或者等于较长单词的长度减一&#xff0c;则这两个单词押韵。换句话说&#xff0c;如果A,B的最长公共后缀LCS&#xff08;A&#xff0c;B&#xff09;≥max&…

bzoj 3668: [Noi2014]起床困难综合症

Description 21 世纪&#xff0c;许多人得了一种奇怪的病&#xff1a;起床困难综合症&#xff0c;其临床表现为&#xff1a;起床难&#xff0c;起床后精神不佳。作为一名青春阳光好少年&#xff0c;atm 一直坚持与起床困难综合症作斗争。通过研究相关文献&#xff0c;他找到了该…

C++解题报告——Kas(动态规划)

题目描述 Kile和Pogi在街上捡到了N张钞票。在确定无法找到失主之后&#xff0c;两人决定将钞票平分。他们想要得到相同数量的钱&#xff0c;所以他们将这些钞票尽可能分成价值相等的两份。但是当钞票无法平分的时候会剩下一些。 由于他们不能将剩余的钞票留在街上&#xff0c;他…