Critical Set(删除无向图的一个节点或者两个节点或者三个节点之后有几个连通分量?)

本文解析了一道关于无向图的编程题,介绍了如何找出图中的关键点(critical point)和关键点集(critical set)。通过删除不同数量的节点来判断是否会导致图分裂,并详细阐述了实现过程和代码细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >




这是棒子的一家公司的一道编程题,写的累死了。

上题目吧,有一个无向图,任意两个定点,都能访问对方,如果我删除一个节点,如果任意两个节点不能访问了,那叫这个点是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[N];
        rank = new int[N];
        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;		
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值