P1141 01迷宫

这题数据有点高级啊(这么高级的数据能不能把它变成黄题呢?不然显得我很垃圾(虽然是事实))

思路

联通块,把周围四格与自己不同的联通起来,看成一个大块,知道要的坐标属于哪个大块并数出大块有多少个点就行了

 

我的第一个想法是先预处理出联通块,然后直接暴力搜索,需要哪个坐标就去搜大块有几个点(想着橙题,随便做都能AC。。

(70分。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005];
int b[1005][1005];
bool c[1005][1005];
int n,m;
void build(int x,int y,int k)
{
    if(x>n || x==0) return; if(y>n || y==0) return ;
    b[x][y]=k;
    if(a[x+1][y]!=a[x][y] && !b[x+1][y]) build(x+1,y,k);
    if(a[x-1][y]!=a[x][y] && !b[x-1][y]) build(x-1,y,k);
    if(a[x][y+1]!=a[x][y] && !b[x][y+1]) build(x,y+1,k);
    if(a[x][y-1]!=a[x][y] && !b[x][y-1]) build(x,y-1,k);
}
int search(int x,int y)
{
    int ans=1;
    if(b[x+1][y]==b[x][y] && !c[x+1][y]) {c[x+1][y]=1; ans+=search(x+1,y);}
    if(b[x-1][y]==b[x][y] && !c[x-1][y]) {c[x-1][y]=1; ans+=search(x-1,y);}
    if(b[x][y+1]==b[x][y] && !c[x][y+1]) {c[x][y+1]=1; ans+=search(x,y+1);}
    if(b[x][y-1]==b[x][y] && !c[x][y-1]) {c[x][y-1]=1; ans+=search(x,y-1);}
    return ans;
}
int main()
{
    int x,y,k=1;
    string s;
    cin>>n>>m;
    memset(a,100,sizeof(a));
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        for(int j=0;j<s.size();j++)
            a[i][j+1]=s[j]-48;
    }//输入的时候是字符串,需要逐字处理
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!b[i][j]){
                build(i,j,k);
                k++;
            }//预处理 ,属于同一个大块的都有相同的K值
    for(int k=1;k<=m;k++)
    {
        cin>>x>>y;
        int ans=0;
        memset(c,0,sizeof(c));
        c[x][y]=1;
        ans=search(x,y);//暴力搜索所属大块有几个点
        cout<<ans<<endl;
    }
    return 0;
}

  

然后就想着改进:感觉每次都暴力数大块有几个点,假如几个点属于同一大块,不就重复数了吗,既然这样,再预处理一下,直接输出答案不就完美了(想到这,感觉这次肯定能AC了。。

(80分。。 这数据真的高级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005];
int b[1005][1005];
bool c[1005][1005];
int d[1005][1005];
int n,m;
void build(int x,int y,int k)
{
    if(x>n || x==0) return; if(y>n || y==0) return ;
    b[x][y]=k;
    if(a[x+1][y]!=a[x][y] && !b[x+1][y]) build(x+1,y,k);
    if(a[x-1][y]!=a[x][y] && !b[x-1][y]) build(x-1,y,k);
    if(a[x][y+1]!=a[x][y] && !b[x][y+1]) build(x,y+1,k);
    if(a[x][y-1]!=a[x][y] && !b[x][y-1]) build(x,y-1,k);
}
int search(int x,int y)
{
    int ans=1;
    if(b[x+1][y]==b[x][y] && !c[x+1][y]) {c[x+1][y]=1; ans+=search(x+1,y);}
    if(b[x-1][y]==b[x][y] && !c[x-1][y]) {c[x-1][y]=1; ans+=search(x-1,y);}
    if(b[x][y+1]==b[x][y] && !c[x][y+1]) {c[x][y+1]=1; ans+=search(x,y+1);}
    if(b[x][y-1]==b[x][y] && !c[x][y-1]) {c[x][y-1]=1; ans+=search(x,y-1);}
    return ans;
}
void build1(int x,int y,int k)//预处理,在d数组直接标出属于同一个大块的点的个数
{
    if(x>n || x==0) return; if(y>n || y==0) return ;
    d[x][y]=k;
    if(b[x+1][y]==b[x][y] && !d[x+1][y]) {d[x+1][y]=k; build1(x+1,y,k);}
    if(b[x-1][y]==b[x][y] && !d[x-1][y]) {d[x-1][y]=k; build1(x-1,y,k);}
    if(b[x][y+1]==b[x][y] && !d[x][y+1]) {d[x][y+1]=k; build1(x,y+1,k);}
    if(b[x][y-1]==b[x][y] && !d[x][y-1]) {d[x][y-1]=k; build1(x,y-1,k);}
}
int main()
{
    int x,y,k=1;
    string s;
    cin>>n>>m;
    memset(a,100,sizeof(a));
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        for(int j=0;j<s.size();j++)
            a[i][j+1]=s[j]-48;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(!b[i][j]){
                build(i,j,k);
                memset(c,0,sizeof(c));
                c[i][j]=1;
                int ans=search(i,j);//搜索出大块有几个点
                build1(i,j,ans);//预处理
                k++;
            }
    for(int k=1;k<=m;k++)
    {
        cin>>x>>y;
        cout<<d[x][y]<<endl;//直接输出结果
    }
    return 0;
}

  

然后实在撑不住,去看了题解。。

每次碰到没搜过的就进行一次搜索,碰到的就直接输出(用数组模拟队列来储存属于同一大块的点的坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
int a[1005][1005];
int c[1005][1005];
int d[1005][1005];
int xx[10000005],yy[1000005];
int n,m;
void search(int x,int y)
{
    int t=1,h=0,ans=0;
    while(h<t)//bfs的队列
    {
        h++;
        x=xx[h]; y=yy[h];
        if(a[x+1][y]!=a[x][y] && !c[x+1][y] && x+1<=n) {t++; c[x+1][y]=1; xx[t]=x+1; yy[t]=y;}
        if(a[x-1][y]!=a[x][y] && !c[x-1][y] && x-1>0) {t++; c[x-1][y]=1; xx[t]=x-1; yy[t]=y;}
        if(a[x][y+1]!=a[x][y] && !c[x][y+1] && y+1<=n) {t++; c[x][y+1]=1; xx[t]=x; yy[t]=y+1;}
        if(a[x][y-1]!=a[x][y] && !c[x][y-1] && y-1>0) {t++; c[x][y-1]=1; xx[t]=x; yy[t]=y-1;}
         
    }
    for(int i=1;i<=t;i++)
        d[xx[i]][yy[i]]=t;//每个属于大块的点都标记上大块点的个数
    return ;
}
int main()
{
    int x,y,k=1;
    string s;
    cin>>n>>m;
    memset(a,100,sizeof(a));
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        for(int j=0;j<s.size();j++)
            a[i][j+1]=s[j]-48;
    }
    for(int k=1;k<=m;k++)
    {
        cin>>x>>y;
        if(!d[x][y]) {c[x][y]=1; xx[1]=x; yy[1]=y; search(x,y);}//如果没搜过就搜
        cout<<d[x][y]<<endl;
    }
    return 0;
}

  

 

posted @   小霜降  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示