点双连通 练习
来源:互联网 发布:linux cat 显示文件名 编辑:程序博客网 时间:2024/04/28 08:02
某个图的点双联通分支里面必然是没有割点存在的, 在搜索树中不停地找,如果找到割点
,我们便将栈中的所有边都找出来,然后放进一个点双连通块中即可。割点可以属于多个双连通块,
但是其他点和边只能属于一个块.
原题就是 亚瑟王要骑士开会, 给一些边,边链接两个骑士,这两个骑士不能坐一起,问最少要减去多少骑士
建立补图,表示边连接的两个骑士可以坐在一起。然后我们要找点连通块中的奇数圈,定理写在代码中了。如果某个骑士
不存在奇数圈中,那么他就不能参加会议。
关于二分图判断问题,用染色法 dfs一下就好了
#include <cstdio>#include <cmath>#include <cstring>#include <ctime>#include <iostream>#include <algorithm>#include <set>#include <vector>#include <sstream>#include <queue>#include <typeinfo>#include <fstream>#include <map>#include <stack>typedef long long ll;using namespace std;const int MAXN = 1010;//点数const int MAXM = 2000005;//边数,因为是无向图,所以这个值要*2struct Edge{ int to,next;}edge[MAXM];int head[MAXN],tot;int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];int Index,top;bool Instack[MAXN];int block; //点双连通块数量//int cut[MAXN]// 记录割点bool ok[MAXN];bool can[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; if( !ok[v]) continue; //如果不在这个联通块中,可以跳过 if(color[v]!= -1){ //若v染过色 ,(初值设为-1) if(color[v]==col) //并且和相邻点颜色相同 return false; continue; //否则继续 } if(!dfs(v,!col)) //!-1 =0 ; return false; } return true;}void Tarjan(int u,int pre){ int v; Low[u] = DFN[u] = ++Index; Stack[top++] = u; Instack[u] = true;// int son=0; // 统计某个点在搜索树中的儿子个数 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); if( Low[u] > Low[v] ) Low[u] = Low[v]; //一条边 (u,v)是桥,当且仅当(u,v)为树枝边(u,v都在栈里面),且满足DFN(u)<Low(v) //这个地方就是对点双连通快进行操作 // // if(u!=pre && Low[v] >= DFN[u] ) // 若找到 割点u ,把边一一取出直到遇见 (u,v) { block++; int vn; cc=0; memset(ok,0,sizeof(ok)); do{ vn=Stack[--top]; Belong[vn]=block; Instack[vn]=0; ok[vn]=1; // 表示这个点是在连通块里面的 tmp[cc++]=vn; } while(vn!=v); // 取完 ok[u]=1; memset(color,-1,sizeof(color)); //初值为-1 //将u点染色为0,判断能否形成二分图 if(!dfs(u,0)){ //定理1:若在该连通分量里面不可形成二分图 ,若为二分图则必有奇数圈,反之也成立 can[u]=1; while(cc--) //定理 2 : 若一个双联通分中某些点在奇数圈中,则所有点也在某个奇数圈中。 can[tmp[cc]]=1; } } } else if( Instack[v] && Low[u] > DFN[v] ) //若 Low[u] = DFN[v]; }}void init(){ tot = 0; memset(head,-1,sizeof(head));}void solve(int n){ memset(DFN,0,sizeof(DFN)); memset(Instack,false,sizeof(Instack));// memset(add_block,0,sizeof(add_block) );// memset(cut,false,sizeof(cut) ); memset(can,0,sizeof(can)); Index=top=block=0; for(int i=1;i<=n;i++) if(!DFN[i]) Tarjan(i,0);// printf("blo=%d\n",block); int ans=n; for(int i=1;i<=n;i++) if(can[i]) ans--; printf("%d\n",ans);}int arc[MAXN][MAXN];int main(){ int n,m; //freopen("1.txt","r",stdin); while(~scanf("%d %d",&n,&m) &&(n||m) ){ init(); int u,v; memset(arc,0,sizeof(arc)); for(int i=0;i<m;i++){ scanf("%d %d",&u,&v); arc[u][v]=arc[v][u]=1; } for(int i=1;i<=n;i++) for(int j=1;j<i;j++){ if(arc[i][j]==0){// printf("%d %d\n",i,j); addedge(i,j); addedge(j,i); } } solve(n); } return 0;}
0 0
- 点双连通 练习
- 边双连通 练习
- hdu 3749 点双连通
- hdu 3394(点双连通)
- POJ 2942 点双连通
- hdu 5739(点双连通)
- HDU 5739(点双连通)
- 割点,桥,双连通分量Tarjan ,入门练习
- poj 2942 双连通 点双连通 边双连通 奇圈
- 无向图的双连通块(点的双连通)&&边的双连通算法
- 点双连通模版 求割点,点双缩点
- poj 2942(点双连通+判奇圈)
- 【图论】割点、桥、双连通
- HDU 5739 (点双连通 树DP)
- 割点、桥、点双连通、边双连通、强连通 题目
- 无向图的割点,割边,点双连通,边双连通模板
- 点双连通分量
- 点双连通分量
- lightoj 1030 Discovering Gold
- Oracle完全卸载详细步骤
- 读冯志伟老前辈的《自然语言处理与现状》
- 自己动手研发P2P功能的IPC摄像头
- java 处理CSV(分号里面有逗号)
- 点双连通 练习
- 常用电脑硬件检测工具下载
- Servlet/JSP各规范与Web服务器Tomcat各版本的对应关系
- Android_AsyncTask
- java配置错误页面方法
- Python文件读写基础
- 冒泡排序
- unbuntu下apache中的django部署
- JSP 6动作