洛谷P1141 //bfs求无向图的子连通块大小(多次询问)

http://www.luogu.org/problem/show?pid=1141

多询问题,求无向图的子连通块大小。

直接bfs,读一个搜一个,过60;

100%的点1,000,000个点,100,000次询问,显然是记忆化。

我很弱,最开始开了个数组记录每个点属于的连通块的第一个点的坐标,然后写了一堆,自己都烦。

后来问某大神,似拨开云雾见到了青天。用cnt记录连通块的" 名字 "。

学会了这一招,不代表过了。

我还是读一个点,如果访问过就输出,没访问就dfs,然后每dfs就循环一次,给所有连通块内的点赋值。代码如下

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<queue>
 7 #include<cstdlib>
 8 #include<algorithm>
 9 #define for1(i,n,m) for(int i=(n);i<=(m);i++)
10 #define for2(i,n,m) for(int i=(n);i>=(m);i--)
11 using namespace std;
12 int n,cnt=1,m,a[1005][1005],ans[1005][1005],v[1005][1005],f1[4]={0,0,1,-1},f2[4]={-1,1,0,0};
13 struct node
14 {
15     int x,y;
16 };
17 queue <node> q;
18
19 void bfs(int x,int y)
20 {
21
22     q.push({x,y});
23     v[x][y]=cnt;
24     int ans1=0;
25     while(!q.empty())
26     {
27         node e=q.front();
28         q.pop();
29         ans1++;
30         for1(i,0,3)
31         {
32             int x1=e.x+f1[i],y1=e.y+f2[i];
33             if(!v[x1][y1]&&a[x1][y1]==3-a[e.x][e.y]&&x1>0&&y1>0&&x1<=n&&y1<=n)
34             {
35
36                 v[x1][y1]=cnt;
37                 q.push({x1,y1});
38             }
39         }
40     }
41     for1(i,1,n)
42     for1(j,1,n)
43     {
44         if(v[i][j]==cnt)
45             ans[i][j]=ans1;
46
47     }
48     cnt++;
49 }
50
51 int main()
52 {
53     cin>>n>>m;
54     for1(i,1,n)
55     for1(j,1,n)
56     {
57         char ch=getchar();
58         while(ch!=‘1‘&&ch!=‘0‘)
59             ch=getchar();
60         if(ch==‘1‘)
61             a[i][j]=1;
62         if(ch==‘0‘)
63             a[i][j]=2;
64     }
65     for1(i,1,m)
66     {
67         int x,y;
68         cin>>x>>y;
69         if(!v[x][y])
70             bfs(x,y);
71         cout<<ans[x][y]<<endl;;
72     }
73 }

超时代码

自己好蠢,根本没好好用上cnt

超时以后去问那个大神

他说复杂度应该是O(n^2+m)

我一脸懵逼

仔细一看他的代码,感觉自己脑子有泡。

之后开了个 t[ i ] 数组作桶,记录属于 i 的联通块的大小。

一遍dfs,求所有连通块,并且分组,分别记录大小。

最后输出。。。

代码如下

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #include<queue>
 7 #include<cstdlib>
 8 #include<algorithm>
 9 #define for1(i,n,m) for(int i=(n);i<=(m);i++)
10 #define for2(i,n,m) for(int i=(n);i>=(m);i--)
11 using namespace std;
12 int n,cnt=1,m,a[1005][1005],ans[1005][1005],f1[4]={0,0,1,-1},f2[4]={-1,1,0,0};
13 int t[1005000];//用一个桶记录每一组的ans
14 int v[1005][1005];//分组,同一个连通块内的点赋相同的值,用cnt计数,以表示连通块的"名字"
15 struct node
16 {
17     int x,y;
18 };
19 queue <node> q;
20
21 int bfs(int x,int y)
22 {
23
24     q.push({x,y});
25     v[x][y]=cnt;
26     int ans1=0;
27     while(!q.empty())
28     {
29         node e=q.front();
30         q.pop();
31         ans1++;
32         for1(i,0,3)
33         {
34             int x1=e.x+f1[i],y1=e.y+f2[i];
35             if(!v[x1][y1]&&a[x1][y1]==3-a[e.x][e.y]&&x1>0&&y1>0&&x1<=n&&y1<=n)
36             {
37
38                 v[x1][y1]=cnt;
39                 q.push({x1,y1});
40             }
41         }
42     }
43     cnt++;
44     return ans1;
45 }
46
47 int main()
48 {
49     cin>>n>>m;
50     for1(i,1,n)
51     for1(j,1,n)
52     {
53         char ch=getchar();
54         while(ch!=‘1‘&&ch!=‘0‘)
55             ch=getchar();
56         if(ch==‘1‘)
57             a[i][j]=1;
58         if(ch==‘0‘)
59             a[i][j]=2;
60     }
61     for1(i,1,n)
62     for1(j,1,n)
63         {
64             if(!v[i][j])
65             {
66                 int tmp=bfs(i,j);
67                 t[cnt-1]=tmp;
68         }}
69     for1(i,1,m)
70     {
71         int x,y;
72         cin>>x>>y;
73
74         cout<<t[v[x][y]]<<endl;
75     }
76 }

时间: 2024-10-05 22:13:30

洛谷P1141 //bfs求无向图的子连通块大小(多次询问)的相关文章

洛谷OJ 1141 01迷宫 暴力(求点所在的联通块大小)

https://www.luogu.org/problem/show?pid=1141 题意:n*n地图,0可以走到相邻的某个1上,1可以走到相邻的某个0上,m次询问,问(x,y)能走到多少个格子? n<=1e3,m<=1e5.若点a能到b,则b也能到a.显然a,b能到达的点相同,同一个联通块内的ans是相同的,即求点所在的连通块大小 #include <bits/stdc++.h> using namespace std; const int N=2e3+20; int dx[4

洛谷——P1141 01迷宫

https://www.luogu.org/problem/show?pid=1141 题目描述 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上. 你的任务是:对于给定的迷宫,询问从某一格开始能移动到多少个格子(包含自身). 输入输出格式 输入格式: 输入的第1行为两个正整数n,m. 下面n行,每行n个字符,字符只可能是0或者1,字符之间没有空格. 接下来m行,每行2个用空格分隔的正整

【RMQ】洛谷P3379 RMQ求LCA

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

强连通分量——消息扩散(洛谷_2002)——tarjan求scc

强连通分量(scc) 缩点 建新图 找入度为0的点 大功告成 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<stack> using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c&g

洛谷p1981 表达式求值

#include <iostream> #include <cstdio> #include <cstring> using namespace std; char s[100007]; typedef long long ll; ll numSt[100007],opSt[100007],ans[63]; int main(){ while(~scanf("%s",s)){ int numTail=0,opTail=0,len=strlen(s),

强连通分量——间谍网络(洛谷_1262)——tarjan求scc

scc 缩点 建图 处理 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<stack> using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'){i

Oil Deposits HDU - 1241 (简单bfs)(找有多少个连通块)

题目链接:https://cn.vjudge.net/problem/HDU-1241 注意:搜索八个方向 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <queue> 5 #include <stack> 6 #include <algorithm> 7 #include <cmath> 8 #include <m

求图的连通块

求连通块 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 这个题目

DFS入门之二---DFS求连通块

用DFS求连通块也是比较典型的问题, 求多维数组连通块的过程也称为--“种子填充”. 我们给每次遍历过的连通块加上编号, 这样就可以避免一个格子访问多次.比较典型的问题是”八连块问题“.即任意两格子所在位置相邻(上下左右对角共八个方位),则在一个连通块.典型例题:HDU 1241 Oil Deposits 传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1241 题目描述:输入m行n列的字符矩阵, 统计字符“@”组成八连块的个数. 题意分析:读入数据