求图的连通块

求连通块


Time Limit: 1sec    Memory Limit:256MB

Description


输入一个简单无向图,求出图中连通块的数目。

Input

 

输入的第一行包含两个整数nmn是图的顶点数,m是边数。1<=n<=1000<=m<=10000

以下m行,每行是一个数对u v,表示存在边(u,v)。顶点编号从1开始。

Output

 

单独一行输出连通块的数目。

Sample Input

5 3

1 2

1 3

2 4

 

Sample Output

2

 

这个题目很简单,我们时需要对整个图运用深度优先搜索。因为深度优先搜索算法需要保证每个顶点都被访问,所以他是依次访问各个独立的块的。因此,我们可以简化搜索算法,同时在里面加入一行统计次数的代码即可。

 

《算法导论》22章,图的基本算法,深度优先搜索。

 

DFS(G)

For each vetex u in V[G]

Do color[u] = white

For each vetex u in V[G]

Do if clolor[u] is white

Then DFS-VISIT(u)

 

DFS-VISIT(u)

Color[u] = gray

For each v in u’s neighbor

If color[v] == white

Then DFS-VISIT(v)

Color[u] = black

#include <stdio.h>
#include <malloc.h>
#include <queue>

using std::queue;

const int MAX = 100;

typedef enum color {
  white = 0,
  gray = 1,
  black = 2
} color;

typedef struct node {
  int data;
  node * next;
  color c;
} node;


bool DFS_Visit(node *G[MAX], int s, int n);
int DFS_blocks(node *G[MAX], int n);
node * tail(node * head);
void print_G(node *G[MAX], int n);

// for test 
void print_G(node *G[MAX], int n) {
  int i;
  node * travel;
  for(i = 0; i < n; i++) {
    travel = G[i];
    printf("%d (color : %d)->", travel->data, travel->c);
    travel = travel->next;
    while(travel != NULL) {
      printf("%d->", travel->data);
      travel = travel->next;
    }
    printf("NULL\n");
  }
  printf("\n");
}

int DFS_blocks(node *G[MAX], int n) {
  int i;
  int res = 0;
  for(i = 0; i < n; i++) {
    G[i]->c = white;
  }

  for(i = 0; i <n; i++) {
    if(DFS_Visit(G, i, n))
      res++;
  }
  return res;
}

bool DFS_Visit(node *G[MAX], int s, int n) {

  if(G[s]->c == black)
    return false;

  G[s]->c = gray;
  queue<node *> q;
  node * u;
  node * travel;
  q.push(G[s]);

  while(!q.empty()) {
    u = q.front();
    q.pop();
    travel = u->next;
    while(travel != NULL) {
      if(G[travel->data-1]->c == white) {
    G[travel->data-1]->c = gray;
    q.push(G[travel->data-1]);
      }
      travel = travel->next;
    }
    // print_G(G ,n);
    u->c = black;
  }

  return true;
}

node * tail(node * head) {
  node * travel = head;
  while(travel -> next != NULL)
    travel = travel->next;
  return travel;
}

int main() {
  int n;  // vetrix shu
  int m; // bian shu
  int v;  // ding dian a
  int u;  // ding dian b

  int i;

  node *G[MAX];
  node * temp1 = NULL;
  node * temp2 = NULL;

  scanf("%d %d", & n, &m);

  for(i = 0; i < n; i++) {
    G[i] = (node *)malloc(sizeof(node));
    G[i]->data = i+1;
    G[i]->next = NULL;
  }

  for(i = 0; i < m; i++) {
    scanf("%d %d", &u, &v);
    temp1 = (node *)malloc(sizeof(node));
    temp1->data = v;
    temp1->next = NULL;
    temp2 = (node *)malloc(sizeof(node));
    temp2->data = u;
    temp2->next = NULL;
    tail(G[u-1])->next = temp1;
    tail(G[v-1])->next = temp2;
  }

  printf("%d\n", DFS_blocks(G, n));

  return 0;
}

参考:

    《算法导论》22章

转载于:https://my.oschina.net/yejq08/blog/364084

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值