蒟蒻本性暴露出来了...
一道黄题,我居然做了两个晚上,刚学广搜不熟练,大佬教的#include<queue>队列做法也不理解,不知道怎么做...感觉自己好菜啊...实在不会做只能黈力一波了,附上一点个人理解,希望多看几篇题解能掌握一些吧......
是的就是这篇题解(对于我这一个没学过图论和记忆化的蒟蒻这个题真是难为人……),但是感觉他的注释和讲解还是不够透彻,这里再解释一下
(吐槽完毕)
首先,这个题要用到连通图(百度百科链接),而且是无向图的连通图;
刚开始不知道怎么把连通图分块,后来想通了,解释一下:
@........@.. .@@@.....@@@ ....@@...@@. .........@@. .........@.. ..@......@.. .@.@.....@@. @.@.@.....@. .@.@......@. ..@.......@.
如图,是一个无向图,这里对于每一个点,如果它的四周有点,就把这些点看做在一个连通块中
直观感受这里是有三个连通块的
这个题不同的是,只有上下左右四个方向,其实是降低了难度的(表示还是不会),分块的操作会简单一些
对于这个无向图,从每一个连通块上的任何一个格子,它的ans都是相同的(自己模拟一下很容易发现)
对于十万组数据,显然需要预处理,我们只需要查找出每一个格子所在的连通块和这个连通块里的元素个数就可以了
还有一个难点,就是这里输入时是没有空格的,所以不能用一般的方法输入
解决办法:控制位数输入和字符数组输入
这里是选择了字符数组输入
AC代码:
#include<cstdio> #include<iostream> #include<cstdlib> #include<iomanip> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<time.h> #include<queue> using namespace std; typedef long long ll; typedef long double ld; typedef pair<int,int> pr; const double pi=acos(-1); #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define Rep(i,u) for(int i=head[u];i;i=Next[i]) #define clr(a) memset(a,0,sizeof a) #define pb push_back #define mp make_pair #define fi first #define sc second ld eps=1e-9; ll pp=1000000007; ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;} ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;} ll read(){ ll ans=0; char last=' ',ch=getchar(); while(ch<'0' || ch>'9')last=ch,ch=getchar(); while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar(); if(last=='-')ans=-ans; return ans; } //head //从这里开始 const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};//表示四个方向 char atlas[1005][1005]; int flag[1005][1005],a[9999999];//flag存每一个格子所在的连通块 int n,m; struct pos { int x,y; }q[9999999]; /*inline bool pan(int x,int y) { if(x>=1&&x<=n&&y>=1&&y<=n&&flag[x][y]==0&&((atlas[x][y]==1&&atlas[q[f].x][q[f].y]==0)||(atlas[x][y]==0&&atlas[q[f].x][q[f].y]==1)) return 1; return 0; }*///未完成的判断函数,烂尾辣 int d,f,r,sum,nx,ny; int main() { n=read(),m=read(); char ch; rep(i,1,n) rep(j,1,n) { cin>>atlas[i][j]; } /*rep(i,1,n) { rep(j,1,n) { cout<<atlas[i][j]<<" "; } cout<<endl; }*///检查读入是否正确 rep(i,1,n) rep(j,1,n) if(flag[i][j]==0)//如果该格还没有连通块包含 { d++;//记录连通块的数量 f=1,r=1;//r记录能够往周围走的格子的数量,f记录是否遍历完 q[f].x=i,q[f].y=j; //记录当前格子的坐标 flag[i][j]=d; sum=1; while(f<=r) { rep(k,0,3)//上下左右搜索 { nx=q[f].x+dx[k],ny=q[f].y+dy[k]; if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&flag[nx][ny]==0&&((atlas[nx][ny]=='1'&&atlas[q[f].x][q[f].y]=='0')||(atlas[nx][ny]=='0'&&atlas[q[f].x][q[f].y]=='1'))) { r++;//如果满足条件,则 sum++;//满足条件,总数累加 flag[nx][ny]=d;//表示当前格子在第几个连通块上 q[r].x=nx,q[r].y=ny; } } f++; } a[d]=sum; } rep(i,1,m) { int sx=read(),sy=read();//输入起点坐标 printf("%d\n",a[flag[sx][sy]]);//直接查找它在哪一个连通块内并输出答案 } return 0; }