C语言数据结构:无向图连通子图

C语言数据结构:无向图连通子图,第1张

C语言数据结构:无向图连通子图

目录

无向图连通子图

问题

参考:

使用队列的代码

遇到的一些问题:

使用栈的代码

正确代码 


无向图连通子图

求无向图连通子图个数

问题

测试数据由m+1行构成,第一行为两个正整数n(1

输出两行信息,第一行输出该图中连通子图的个数。第二行按照升序输出每个连通子图中顶点个数。

参考:

求大神赐教:找出无向图的所有连通子图算法? - 知乎

<数据结构>无向连通子图个数求解(C语言版)_djs_snowyyy的博客-CSDN博客_无向图的连通子图个数

理解题意:

 连通图是“任意两点之间都可以联通的”。

 我感觉我的思路还是比较混乱的,这份代码最后的分数也只有60。目前还没改好。

使用队列的代码
for(i=0;i
#include 

typedef struct QNode{
    int elem;
    struct QNode * next;
}QNode;
//创建链式队列的函数
QNode * initQueue(){
    //创建一个头节点
    QNode * queue=(QNode*)malloc(sizeof(QNode));
    //对头节点进行初始化
    queue->next=NULL;
    return queue;
}
//入队 
QNode* enQueue(QNode * rear,int elem){  
    QNode * enElem=(QNode*)malloc(sizeof(QNode));
    enElem->elem=elem;enElem->next=NULL;//1、用节点包裹入队元素
    rear->next=enElem;//2、新节点与rear节点建立逻辑关系
    rear=enElem;//3、rear指向新节点
    //返回新的rear,为后续新元素入队做准备
    return rear;
}
//出队
int DeQueue(QNode * top){
    if (top->next==NULL) {
        //printf("队列为空n");
        return 0;
    }
    QNode * p=top->next;
    top->next=p->next;
    free(p);
    return 1;
} 
//————————————————
int main()
{	//BFS 
	int n,m,t,i,j,count=0;
	int graph[31][31]={0};//图的邻接矩阵
	int outcome[20]={0};//存放结果的顶点数 
	int mark[31]={0};//用来标记 

	scanf("%d%d",&n,&m);
	for(t=0;tnext==NULL)
					break;
				p=top->next;//查看此时队列第一个元素 
				t=p->elem;
				for(a=1;a<=n;a++)//判断邻接 
				{
					if(graph[t][a]&&mark[a]==0&&t!=a)
					{//邻接+未访问+非本身  
						mark[a]=1;
						len++;
						rear=enQueue(rear,a);//入队 
					}
				}
				DeQueue(top);//首出队 
			}
				outcome[j]=len;j++;count++;//visit results  		
		 } 
	} 
	printf("%dn",count);
	//起泡排序
	for(i=0;ii;j--)
		{
			if(outcome[j-1]>outcome[j])
			{
				t=outcome[j-1];
				outcome[j-1]=outcome[j];
				outcome[j]=t;
				len=0;
			}
		}
		if(len)
			break;
	}
	 
	for(i=0;i 
遇到的一些问题: 

①计数从0开始还是1开始,全局记得统一 。
②出现了变量太多不知道含义的错误,并且分不清参量的用途。写着的感受就是:乱。
③没有办法进入下一轮 --->每一次新建队列而不是用旧的、deQuenue完的空队。(好像也不一定,好像是我的问题) 
④用1维的数组标记就可以,不用2维数组。因为如果出现,那么它必然只能出现一次。本质上来说,只需要遍历一次就可以。
⑤注意考虑只有一个点情况,即从a点出发的边又指向a点。 

使用栈的代码

同样也是60分 

①多余的mark数组和计算顶点数目的数组完全没有必要,合理充分利用邻接矩阵,同时也减少了变量数目

②用stack,这样我就少些了队列定义的代码,我不会队列嘛:D

③没有多余的子函数,全部在主函数中用循环结构遍历

#include
#include
using namespace std;

int main()
{
	int n,m,t,i,j,count=0;
	int array[31][31]={0};
	cin >> n >> m;
	for (t = 1; t <= m; t++) 
	{
		cin >> i >> j;
		array[j][i] = 1;array[i][j] = 1;
		array[i][0] =-1;array[j][0] =-1;
	}
	
	for(i=1;i<=n;i++)
	{
		if(array[i][0]==-1)//有节点,并且没有被访问过 
		{ 
			stack graph;//使用栈的数据结构进行dfs搜索 
			graph.push(i);//这个节点入栈
			count++;
			array[i][0]++;//入栈时标记该节点已经被访问过 
			array[0][i]++;//此位置记录此子图所含元素个数,入栈时标记 
			while(graph.size())//循环:非空
			{
				j=graph.top();
				graph.pop();
				for(t=1;t<=n;t++)
				{//条件:连通+未访问过 
					if(array[j][t]&&array[t][0]==-1)
					{
						//先标记
						array[0][i]++;array[t][0]++;
						graph.push(t); 
					}
				}
			 } 
		}
	//	printf("%d号子图含有顶点%dn",i,array[0][i]);
	}
	printf("%dn",count);
	//需要对答案排序之后输出
	//虽然要求从小到大,但是可以嗯反过来 
	int flog;
	for(i=1;i<=n;i++)
	{
		flog=1;
		for(j=n;j>i;j--)
		{
			if(array[0][j-1]0;i--)
	 	printf("%d ",array[0][i]);
	return 0;
}
正确代码 

 不改了,附上我同学正确代码。好羡慕别人提交一次就对一次。

#include 
#include 
using namespace std;
int main() {
	int m, n;
	cin >> n >> m; //顶点数,边数
	
	int a[n + 1][n + 1] = {0};//邻接矩阵表示
	int b[n + 1] = {0}; //存放每个连通子图顶点数
	
	for (int i = 1; i <= m; i++) 
	{
		int x, y;
		cin >> x >> y;
		a[x][y] = 1;
		a[y][x] = 1;
	}
	
	int q = 0; //当前遇到过q个连通子图
	for (int i = 1; i <= n; i++) 
	{
		if (a[i][0] == 0) //条件限制重复访问。同时第一次是能够进去的。 
		{ //这个顶点目前不属于任何连通子图
		q++;//连通子图+1
		stack s;
		s.push(i);//子图第一个定点入栈
		//b[i]++; //每入栈一个元素,说明子图顶点数+1
			while (!s.empty()) 
			{ //寻找与q相连的所有顶点
		
				int now = s.top(); //出栈
				s.pop();
				if (a[now][0] == 0) 
				{//防止栈中元素为12344时对“4“的重复处理
					b[i]++; //说明子图顶点数+1
					a[now][0] = q; //标记这个顶点属于第q个子图
				
					for (int j = 1; j <= n; j++) 
					{ //遍历与他相连的顶点,把不属于任何子图的进栈
						if (a[now][j] == 1 && now != j && a[j][0] == 0) {
						s.push(j);//入栈
						//b[i]++; //每入栈一个元素,说明子图顶点数+1
						}//if
					}//for
				}//if
			}//while
		}//if
	}//for
	
	cout << q << endl;
	for (int i = 1; i <= n - 1; i++)
	{ //选择排序从小到大
		for (int j = i + 1; j <= n; j++) 
		{
			if (b[j] < b[i]) 
			{
				int t = b[i];
				b[i] = b[j];
				b[j] = t;
			}//if
		}//for
	}//for
	for (int i = 1; i <= n; i++)
		if (b[i] != 0)
			cout << b[i] << " ";
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5670811.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存