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;
}
评论列表(0条)