点双连通分量
来源:互联网 发布:网络医疗美容咨询 编辑:程序博客网 时间:2024/04/30 02:30
/*补图:对于一个无向图G,他的完全图为K,那么K-G的所有边组成的图就是G的补图双连通分量:无向图G的一个极大双连通子图,这个子图要分成多个子图的话必须舍弃2极其以上的点或者边二分图:把无向图的顶点划分成两个部分,无向图的边两端的顶点分别属于这两个部分,也就是说在顶点集合内部不会有边连接交叉染色法:判定一个图是否二分图的方法奇圈:无向图中一条长度为奇数的回路,他的点和边不重合*/ /*一个双连通分量的某些顶点在一个奇圈中,则他的其他节点也在某个奇圈中含有奇圈的双连通分量不是二分图,二分图不含奇圈*///POJ2942 //思维转换//因为憎恨图中的骑士是不能被选中的,那么对憎恨图求补图,补图中的骑士是可以选中的//因为要求每个骑士旁边有两个人,所以要求补图中的点双连通分支//因为要求选中的人为奇数个,所以点双连通分支含有奇圈,有奇数个顶点const int maxn = 1010 ;const int maxm = 2* 1e6 + 10 ;struct Edge{ int to , next ;}edge[maxm];int head[maxn] , tot ;int Low[maxn ] , DFN[maxn] , Stack[maxn] , Belong[maxn] ;int Index , top ;//点连通分量的个数 int block ;bool Instack[maxn] ;bool can[maxn] ;bool ok[maxn] ;//存储双连通分量的点 int tmp[maxn] ;int cc ;//染色 int color[maxn] ;void addedge( int u , int v){ edge[tot].to = v ; edge[tot].next = head[u] ; head[u] = tot ++ ;}//交叉染色法判断二分图 bool dfs( int u , int col){ //染色 color[u] = col ; for(int i = head[u] ; i!= -1 ;i= edge[i].next ){ int v = edge[i].to ; //现在被判定的双连通分量的点都被打上ok标记,代表可以染色,否则就是一些不在双连通的点不管他 if( !ok[v ]) continue ; //代表已经被染色的点,他肯定是在双连通分量里面的,因为之前上一步判定为ok可以染色 if( color[v] != -1){ //边的两个端点染上同一种颜色,那么不是二分图 if( color[v] == col ) return false ; //之前已经访问的节点但是染上的是不同的颜色,不管他,即不通过他进行搜索 continue ; } //经过上一步判定了这个点肯定是没有染过色的,对这一个节点用不同的颜色染色 if( !dfs(v , !col )) return false ; } return true ;} void Tarjan( int u , int pre){ int v ; Low[u] = DFN[u] = ++Index ; Stack[top ++ ] = u ; Instack[u] = true ; for( int i = head[u] ; i!= -1 ; i=edge[i].next ){ v = edge[i].to ; if( v == pre) continue ; //树枝边 if( !DFN[v]){ Tarjan( v , u ) ; //之前有个回向边是Low[v]变小 if( Low[u] > Low[v]) Low[u] = Low[v] ; //点连通分量,割点 v if( Low[v] >= DFN[u]){ block ++ ; //点连通分量 int vn ; cc = 0 ; //双连通分量中的点 memset( ok , false , sizeof( ok )) ; do{ vn = Stack[--top ] ; Belong[vn] = block ; Instck[vn] = false ; ok[vn] = true ; tmp[ cc ++] = vn ; } while( vn != v) ; ok[u] = 1 ; memset( color , -1 , sizeof( color )) ; //非二分图,交叉染色法判定图是否二分图,二分图不含有奇圈,含有奇圈的肯定不是二分图 if( !dfs(u , 0 )) { can[u] = true ; while( cc -- ) //该双连通分量的所有骑士都可以参加会议,割点可以属于多个双连通分量,而其他点只能属于一个连通分量 can[ tmp[cc]] = true ; } } } } else if( Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v] ;} void solve( int n ){ memset( DFN , 0 ,sizeof( DFN )) ; memset( Instack , false , sizeof( Instack )) ; Index = block = top = 0 ; memset(can , false , sizeof( can )) ; for( int i = 1; i<=n ;i++) if( !DFN[i] ) Tarjan( i , -1 ) ; //统计需要被驱逐的骑士 int ans = n ; for( int i = 1 ; i<=n; i++) if( can[i] ) ans -- ; printf("%d\n" , ans ) ;}void ini() { tot = 0 ; memset( head , -1 , sizeof( head )) ;}int g[maxn][maxn] ;int main(){ int n , m ; int u , v ; while(scanf("%d%d" , & n , & m ) == 2) { if( n == 0 && m == 0) break ; ini() ; memset( g , 0 ,sizeof( g )) ; while(m -- ){ scanf("%d%d", & u , & v) ; //憎恨关系 g[u][v] = g[v][u] = 1 ; } //求补图 for( int i =1 ;i<=n ;i++){ for( int j =1 ;j<=n ;j++) if( i != j &&g[i][j] ==0 ) addedge(i , j ) ; } solve( n ) ; } return 0 ;}
阅读全文
0 0
- 点双连通分量
- 点双连通分量
- 点双连通分量
- 点双连通分量
- 点-双连通分量模板
- 求点双连通分量
- 点-双连通分量&边-双连通分量复习笔记
- POJ 2942 点的双连通分量
- 计算点-双连通分量算法
- poj2942 点双连通分量
- 割点、桥、双连通分量
- 割点 桥 双连通分量模版
- 点/边 双连通分量---Tarjan算法
- POJ1523 SPF【点双连通分量】【Tarjan】
- tarjan求点的双连通分量
- 点的双连通分量问题
- hdu3749 Financial Crisis(点-双连通分量)
- HDU 3394 Railway 点双连通分量
- HDU1348
- java简单画图板实现
- tensorflow 持久化原理
- 读取手机联系人简单方法(id,姓名,手机号)
- HDU 6063 RXD and math【数学】
- 点双连通分量
- 左式堆 C 实现~~
- Windows命令远程执行工具Winexe
- Linux的crontab使用
- subline 安装Package Control EMMET
- I/O多路转接之poll
- 【JavaScript】我的第4个例子-实例解析
- 使用Nexus搭建Maven私服(二)
- OpenCV学习(3) OpenCV框架