信息学奥赛一本通(1249:Lake Counting)

1249:Lake Counting


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 9435     通过数: 4902

【题目描述】

题意:有一块N×M的土地,雨后积起了水,有水标记为‘W’,干燥为‘.’。八连通的积水被认为是连接在一起的。请求出院子里共有多少水洼?

【输入】

第一行为N,M(1≤N,M≤110)。

下面为N*M的土地示意图。

【输出】

一行,共有的水洼数。

【输入样例】

10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.

【输出样例】

3

【分析】

        这道题同细胞题目,属于图连通性问题,遍历地图,判断如果该点是水——'W',则将该点改为陆地——'.' ,表示不返回。可以用深搜实现,也可以用广搜实现,深搜代码如下:

【参考代码1】

#include<stdio.h>
#include <string.h>

char a[1001][1001];
int n,m;
void dfs(int x,int y)
{
    int i,j,b,c;
    for(i=-1;i<2;i++)  // 遍历九宫格 
	{
        for(j=-1;j<2;j++)
		{           //(x,y)原点,
            b=x+i;  //(x-1,y-1)左上、(x-1,y)上、(x-1,y+1)右上、(x,y-1)左、 
            c=y+j;  //(x,y+1)右、(x+1,y-1)左下、(x+1,y)下、(x+1,y+1)右下 
            if(i==0 && j==0)
            	continue;   // 原点 
            if(b>=0 && b<n && y>=0 && y<m && a[b][c]=='W') // 边界判断和水判断 
            {
                a[b][c]='.'; // 如果该点是'W',就改点为'.',以后也不访问它 
                dfs(b,c);    // 去搜索该点
            }
        }
    }
}
int main()
{
    int i,j,num=0;
    scanf("%d %d",&n,&m);
    memset(a,'0',sizeof(a));
    for(i=0;i<=n-1;i++)
    	scanf("%s",a[i]);
    
    for(i=0;i<n;i++)
	{
        for(j=0;j<m;j++)
		{
            if(a[i][j]=='W')
			{
                num++;//遇见一个水洼 就加加
                dfs(i,j);//去搜索这一点的八个方向
            }
        }
    }
    printf("%d\n",num);
    return 0;
}

【参考代码2】

广搜C++代码如下:

#include <iostream>
#include <cstdio>
#include <queue>

using namespace std;
struct node
{
    int x;
    int y;
};
const int N=200;

int n,m;
char mapp[N][N];      //地图数组 
int vis[N][N];        //访问数组
int dir[][2]={{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,-1},{-1,1}};  //方向数组 
int sum;

void bfs(int x,int y)
{
	queue <node> q;
	node st;
	//标记起点
	st.x = x;
	st.y = y;
	 
    mapp[x][y]='.';
    vis[x][y]=1;
    q.push(st);
    
    while(!q.empty())
	{
        node a=q.front();
        for(int i=0;i<8;i++)        // 沿8个方向扩展 
		{
			node nw;
            nw.x = a.x + dir[i][0];
            nw.y = a.y + dir[i][1];
            if(nw.x >=0 && nw.x<n && nw.y>=0 && nw.y<m && (mapp[nw.x][nw.y]=='W'))
			{
                mapp[nw.x][nw.y]='.';
                q.push(nw);
            }
        }
        q.pop();
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%s",mapp[i]);
    
    for(int i=0;i<n;i++)
	{
        for(int j=0;j<m;j++)
		{
            if(mapp[i][j]=='W')
            {
                sum++;
                bfs(i,j);
            }
        }
    }
    printf("%d\n",sum);
    return 0;
}

【参考代码3】

广搜C代码如下:

#include<stdio.h>
#define N 100010
struct node
{
    int x;
    int y;
}q[N];

int n,m;
char a[120][120];
int dir[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,1},{1,1},{1,-1},{-1,-1}};

void bfs(int x0,int y0)
{
    int i,head=1,tail=1;
    int x,y;
    int nx,ny;

    a[x0][y0]='.';
    q[tail].x=x0;
    q[tail].y=y0;
    tail++;

    while(head<tail)
    {
        x=q[head].x;
        y=q[head].y;
        for(i=0;i<8;i++)
        {
            nx=x+dir[i][0];
            ny=y+dir[i][1];
            if(nx>=0 && nx<n && ny>=0 && ny<m && a[nx][ny]=='W')
            {
                a[nx][ny]='.';
                q[tail].x=nx;
                q[tail].y=ny;
                tail++;
            }
        }
        head++;
    }
}
int main()
{
    int i,j,sum=0;
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
        scanf("%s",a[i]);
    for(i=0;i<n;i++)
        for(j=0;j<m;j++)
            if(a[i][j]=='W')
            {
                sum++;
                bfs(i,j);
            }
    printf("%d\n",sum);
    return 0;
}

http://ybt.ssoier.cn:8088/problem_show.php?pid=1249

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`std::counting_semaphore` 是 C++20 新增的同步原语之一,用于控制多个线程间的访问。它是一个计数信号量,可以用来限制同时访问某个资源的线程数量。在类的成员中使用 `std::counting_semaphore` 与在其他地方使用它并没有本质的区别,只需要在类的定义中声明一个 `std::counting_semaphore` 类型的成员即可。 以下是一个简单的示例代码: ```c++ #include <semaphore> #include <thread> #include <iostream> class Example { public: Example() : sema_(2) {} void do_something() { sema_.acquire(); std::cout << "Doing something..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); sema_.release(); } private: std::counting_semaphore<2> sema_; }; int main() { Example e; std::thread t1(&Example::do_something, &e); std::thread t2(&Example::do_something, &e); std::thread t3(&Example::do_something, &e); t1.join(); t2.join(); t3.join(); return 0; } ``` 在这个例子中,`Example` 类中定义了一个 `std::counting_semaphore<2>` 类型的成员 `sema_`,用于控制同时访问 `do_something` 函数的线程数量。在 `do_something` 函数中,线程首先需要调用 `acquire()` 函数获取信号量,如果当前已经有两个线程在访问,则该线程会被阻塞,直到有一个线程调用了 `release()` 函数释放了信号量。在主函数中,我们创建了三个线程来同时访问 `do_something` 函数,由于信号量的数量是 2,因此最多只有两个线程能够同时访问,第三个线程需要等待前面的线程释放信号量后才能继续执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值