Critical Set(删除无向图的一个节点或者两个节点或者三个节点之后有几个连通分量?)
2014-09-16 17:18
537 查看
这是棒子的一家公司的一道编程题,写的累死了。
上题目吧,有一个无向图,任意两个定点,都能访问对方,如果我删除一个节点,如果任意两个节点不能访问了,那叫这个点是critical point;如果说删除一个不行,那么删除两个或者三个才行,那么叫critical set,最多删除三个。
题目
输入是一个文件,文件的格式如下4
9 10
1 2 1 7 1 3 3 5 2 3 2 4 6 8 6 9 9 8 5 8
9 12
1 2 1 5 2 5 2 3 5 6 3 6 3 4 6 7 7 8 4 8 8 9 4 9
5 7
1 2 1 3 1 5 2 5 4 5 2 4 3 4
6 11
1 2 1 6 2 6 1 3 2 3 3 4 4 5 5 6 2 4 3 6 2 5
说明一下,第一行是有多少case,没两行是一个case。一个case里,第一行是 顶点数与边数,第二行是每两个数为一单元,两个数表示两个顶点,这两个顶点之间有边。
输出是:
case #1 1 1
case #2 2 2 5
case #3 2 1 4
case #4 3 2 3 5
每行写一个case,最前面写case #几,之后第一个数表示有几个critical point,1表示一个,2表示两个,3表示3个,-1表示不存在critical set。
思路
先删除一个点,只要把与它相关的边删除即可,然后开始查找图有几个连通分量,如果连通分量超过2个,那么就是存在critical point;如果删除一个点不行,那么删除两个点,再检测联通分量,如果联通分量大于3,那么存在critical point;如果还不行,删除三个点,依然是检测连通分量,思路与上面是一样的。怎么检测联通分量呢?
假如说刚开始每个点都是一个独自集合,如果两个点之间有条边,那么这两个集合并成一个集合。
下面看代码吧
#include<iostream> #include<fstream> using namespace std; struct critiSec{ int pointNum; int *pointData; critiSec(int n):pointNum(n),pointData(NULL){} }; class Union { private: int* id; // id[i] = parent of i int* rank; // rank[i] = rank of subtree rooted at i (cannot be more than 31) int count; // number of components public: Union(int N) { count = N; id = new int ; rank = new int ; for (int i = 0; i < N; i++) { id[i] = i; rank[i] = 0; } } ~Union() { delete [] id; delete [] rank; } int find(int p) { while (p != id[p]) { id[p] = id[id[p]]; // path compression by halving p = id[p]; } return p; } int getCount() { return count; } bool connected(int p, int q) { return find(p) == find(q); } void connect(int p, int q) { int i = find(p); int j = find(q); if (i == j) return; if (rank[i] < rank[j]) id[i] = j; else if (rank[i] > rank[j]) id[j] = i; else { id[j] = i; rank[i]++; } count--; } }; class Graph{ private: int Vertexs; int **Edges; int **backEdges; public: Graph(int V,int **E):Vertexs(V){ Edges=new int*[Vertexs]; for(int i=0;i<Vertexs;i++){ Edges[i]=new int[Vertexs]; } backEdges=new int*[Vertexs]; for(int i=0;i<Vertexs;i++){ backEdges[i]=new int[Vertexs]; } for(int i=0;i<Vertexs;i++) for(int j=0;j<Vertexs;j++){ Edges[i][j]=E[i][j]; backEdges[i][j]=E[i][j]; } } void deletePoint(int i){ for(int j=0;j<Vertexs;j++){ Edges[i][j]=0; Edges[j][i]=0; } } ~Graph(){ for(int i=0;i<Vertexs;i++){ if(Edges[i]) delete []Edges[i]; } if(Edges) delete []Edges; } critiSec* CriticalSet(); int isConnect(); void deleteEdge(int i,int j){ Edges[i][j]=0; Edges[j][i]=0; } void restoreEdge(int i){ for(int k=0;k<Vertexs;k++){ Edges[k][i]=backEdges[k][i]; Edges[i][k]=backEdges[i][k]; } } }; critiSec* Graph::CriticalSet(){ bool flag=false; critiSec *cr=NULL; for(int i=0;i<Vertexs;i++){ deletePoint(i); if(3==isConnect()){ flag=true; cr=new critiSec(1); cr->pointData=new int(i); cr->pointData[0]=i; restoreEdge(i); break; } restoreEdge(i); } if(!flag){ for(int i=0;i<Vertexs-1;i++){ deletePoint(i); if(flag) break; for(int j=i+1;j<Vertexs;j++){ deletePoint(j); if(4==isConnect()){ flag=true; cr=new critiSec(2); cr->pointData=new int[2]; cr->pointData[0]=i; cr->pointData[1]=j; break; } restoreEdge(j); deleteEdge(i,j); } restoreEdge(i); } } if(!flag){ for(int i=0;i<Vertexs-2;i++){ if(flag) break; deletePoint(i); for(int j=i+1;j<Vertexs-1;j++){ if(flag) break; deletePoint(j); for(int k=j+1;k<Vertexs;k++){ deletePoint(k); if(5==isConnect()){ flag=true; cr=new critiSec(3); cr->pointData=new int[3]; cr->pointData[0]=i; cr->pointData[1]=j; cr->pointData[2]=k; break; } restoreEdge(k); deleteEdge(j,k); deleteEdge(i,k); } restoreEdge(j); deleteEdge(j,i); } restoreEdge(i); } } if(!flag) cr=new critiSec(-1); return cr; } int Graph::isConnect(){ Union uniCon(Vertexs); for(int i=0;i<Vertexs;i++){ for(int j=i+1;j<Vertexs;j++){ if(Edges[i][j]) uniCon.connect(i,j); } } return uniCon.getCount(); } int main(){ ifstream file; ofstream out; out.open("out.txt",ios::out); file.open("graph.txt",ios::in); if(file.fail()){ cout<<"open files fails"<<endl; return 0; } int caseNum; file>>caseNum; for(int i=0;i<caseNum;i++){ int edgeNum,v; file>>v>>edgeNum; int **e=new int*[v]; for(int i=0;i<v;i++){ e[i]=new int[v]; memset(e[i],0,sizeof(int)*v); } int v1,v2; for(int i=0;i<edgeNum;i++){ file>>v1>>v2; e[v1-1][v2-1]=1; e[v2-1][v1-1]=1; } Graph g(v,e); critiSec *cr=g.CriticalSet(); switch(cr->pointNum){ case -1: out<<"case #"<<i+1<<" "<<-1<<endl; break; default: out<<"case #"<<i+1<<" "<<cr->pointNum<<" "; for(int k=0;k<cr->pointNum;k++) out<<cr->pointData[k]+1<<" "; out<<endl; } delete []cr->pointData; delete cr; for(int i=0;i<v;i++) delete []e[i]; delete []e; } out.close(); file.close(); return 0; }
相关文章推荐
- 一个整型数组里除了一个或者两个或者三个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)
- 函数模板】求两个整数 或者三个整数中的最大数 自动判断你输入的是几个整数
- Zoj 1119 POJ 1523 SPF 求关节点及删除关节点会出现多少个连通分量 Tarjan算法
- 在搭建好Hadoop集群后,namenode与datanode两个过程不能起来,或者一个启动之后另一个自动关闭
- RAC数据库当归档文件两个节点都能访问时,就能在一个节点上进行备份及删除
- poj 1523 求无向图所有割点以及删除割点后连通分量个数 给出详细算法思路
- writeObject可以写n个,但是readObject()却只能读一次,你做一下测试。 如果你需要序列化好几个类的话,建议你用json;或者自己写两个方法,一个是将对象转换为字符串,一个是将字符串
- CareerCup2.3 删除最中间那个,或者删除给出任意一个节点(只能得到这个节点的pointer)
- HDU 4587 TWO NODES 删除两个点求连通分量
- 删除文件,若文件所在目录下只有一个文件则递归删除文件所在目录,直到删除的所在目录下有两个文件或者文件夹
- hdu 4587 推断孤立点+割点+ 删除点之后,剩下多少连通分量
- mysql查询根据一个字段或者两个字段内容重复的记录并将其全部删除
- 一个整型数组里除了一个或者两个或者三个数字之外,其他的数字都出现了两次。
- 一个整型数组里除了一个或者两个或者三个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)
- 一个整型数组里除了一个或者两个或者三个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)
- 关于最小生成树中的kruskal算法中判断两个点是否在同一个连通分量的方法总结
- soj 3134: windy和水星 Stoer-Wagner算法求无向图的最小割集:一个无向连通网络,去掉一个边集可以使其变成两个连通分量则这个边集就是割集;最小割集当然就权和最小的割集
- 数据结构:设有一个不带头结点的单链表L,设计两个递归算法,del(L,x)删除单链表L中第一个值为x的节点,delall(L,x)删除单链表L中的最小节点值。
- 创业日志:一个和尚挑水喝,两个和尚抬水喝,三个和尚没水喝?
- 这是一个关于XML文档的操作管理器XMLHelper类,类中包括XML文档的创建,文档节点和属性的读取,添加,修改,删除的方法功能的实现