求图的连通块

求连通块

Time Limit: 1sec    Memory Limit:256MB

Description

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

Input

输入的第一行包含两个整数n和m,n是图的顶点数,m是边数。1<=n<=100,0<=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章

时间: 2024-08-21 16:46:05

求图的连通块的相关文章

6_12 油田(UVa572)&lt;图的连通块DFS&gt;

有一家石油公司负责探勘某块地底下的石油含量,这块地是矩行的,并且为了探勘的方便被切割为许多小块.然后使用仪器对每个小块去探勘.含有石油的小块称为一个pocket.假如两个pocket相连,则这两个pocket属于同一个oil deposit.(所谓相连的定义与踩地雷游戏中的定义相同,请参考sample input,sample output)你的任务就是要找出这块地包含几个不同的oil deposit.Input输入包含好几组数据,每组数据的第一行有2个整数m,n.m代表这块地的列数,n代表这块

求水洼的问题(或者是说求图中连通子图的个数)----深度优先算法

遇到这个题的时候,不太容易快速的想到思路:可能会比较容易想到使用递归的思想:但是具体怎么写呢?其实这个题就相当于是图论中的求连通图,很容易应该想到的是深度优先搜索或者是广度优先搜索:我们就用深度优先算法来求这个题目:直接求有几个区域不好求,那么我们换个思路来求,这种题就是这样,直接求不好求,但是当我们转换一下思路之后就豁然开朗: 我们遍历所有的点,当遇到有水的点时,就将它周围的(八个方向)所有的水点都消除:所以在主遍历for循环中遇到几个水点就是有几个水洼: /*****************

UVa572 Oil Deposits (DFS求连通块)

链接:http://acm.hust.edu.cn/vjudge/problem/19435分析:DFS求图的连通块.每次从图中找出一个未访问过的‘@’开始递归遍历它周围的‘@’格子,将访问到的‘@’标上id存在idx数组中,dfs的次数就是连通块的个数.DFS遍历用递归实现,BFS用队列实现.DFS和BFS实现种子填充:https://zh.wikipedia.org/wiki/Flood_fill 1 #include <cstdio> 2 #include <cstring>

CSUOJ 1601 War (离线并查集求连通块个数)

1601: War Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 130  Solved: 38 [Submit][Status][Web Board] Description AME decided to destroy CH's country. In CH' country, There are N villages, which are numbered from 1 to N. We say two village A and B ar

逆向思维 + 用并查集动态维护连通块的个数——Luogu P1197题解

题目大意: 给你一个 $ n $ 个点的图与 $ m $ 条边,接下来给出一个长度为 $ k $ 个整数,按照给出整数的顺序依次删掉对应编号的点,求出一开始的连通块的个数与接下来每次删除一个点后的连通块的个数.(连通块就是一个点集,这个集合里面的任意两个点都可以互相到达) 思路: 大体思路: 这个题目如果正向考虑会很难做,因为我们要每次维护一个不断删点的图的连通块个数是很难弄的.所以我们要倒着考虑.假如我们把删点的过程倒着考虑,就变成了从最后一个点往前添加进这个图里面的过程.所以这样问题就变成了

POJ 2117--Electricity【点双联通 &amp;&amp; 求删去一个点后,图最多有多少块连通】

Electricity Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4589   Accepted: 1512 Description Blackouts and Dark Nights (also known as ACM++) is a company that provides electricity. The company owns several power plants, each of them sup

nyoj27-水池数目 (求连通块数目)【dfs】

http://acm.nyist.net/JudgeOnline/problem.php?pid=27 水池数目 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 南阳理工学院校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处是否是水池,现在,你的任务来了,请用计算机算出该地图中共有几个水池. 输入 第一行输入一个整数N,表示共有N组测试数据每一组数据都是先输入该地图的行数m(0<m<100)与列数n(0

UVA 572 Oil Deposits油田(DFS求连通块)

UVA 572     DFS(floodfill)  用DFS求连通块 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Description Due to recent rains, water has pooled in various places in Farmer John's field, which is represented by a rectangle of N x M

UVa 572 油田(DFS求连通块)

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=513 终于开始接触图了,恩,开始接触DFS了,这道题就是求连通分量,比较简单. 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 int m, n; //记录连通块的数量 6 cha