鱼C论坛

 找回密码
 立即注册
查看: 2264|回复: 10

[已解决]求助

[复制链接]
发表于 2023-5-3 16:52:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
给蜗蜗留口气
Statement
Submit
Custom Test
蜗蜗最近爱上了下蜗蜗棋,蜗蜗棋和地球上的围棋有相似之处。他最近在分析自己以前下过的一些残局(即将结束的棋局)。

现在有一个 n×n
的棋盘。每个位置有一个数,这个数为 0
,则表示这里没有棋子,是空的;这个数为 1
,则这里有一颗黑棋;这个数为 2
,则这里有一颗白棋。一颗棋有多少“气”,取决于它周围位置的状态。对于每颗棋子,它的上下左右四个方位上距离它最近的位置中,有几个是空着的,那它就有几口“气”,特别的,如果这个棋子在边上或者角上,意味着它某些方向上的位置已经出了棋盘,那么,虽然那里没有棋子,但也不能算是有“气”。

例如对于一颗棋子,它包括上下左右的状态如下:

  1
0 1 0
  2
对于中间的那个 1
,它有 2
口“气”。因为它左右两边是空着的。

蜗蜗用的是白棋,请你帮他计算一下,他的棋子总共有多少口“气”。注意,计算所有棋子的“气”的总和时,一个 0
只能被当作一口“气”,不能重复计算。

输入格式
第一行一个正整数 n


接下来 n
行,每行 n
个数( 0
或者 1
或者 2
),中间用空格隔开,表示棋盘状态。

输出格式
一行, 一个整数,表示蜗蜗的棋子总共有多少口“气”。

样例输入1
3
2 0 2
0 1 1
2 1 0
样例输出1
2
样例输入2
4
0 1 1 0
1 2 2 1
1 2 0 1
0 1 0 0
样例输出2
1
数据范围
对于 100%
的数据,保证 1≤n≤1000



我的代码只得到了10分:
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,sum=0;
  4. int a[1005][1005];
  5. int main(){
  6.         scanf("%d",&n);
  7.     for(int i=1;i<=n;i++)
  8.     {
  9.                 for(int j=1;j<=n;j++)
  10.                 {
  11.                         scanf("%d",&a[i][j]);
  12.                             if(a[i][j]==0){
  13.                                         if(a[i-1][j]==2||a[i+1][j]==2||a[i][j+1]==2||a[i][j-1]==2)
  14.                                            sum++;
  15.                                 }
  16.                 }
  17.         }
  18.         printf("%d\n",sum);
  19.         return 0;
  20. }
复制代码
最佳答案
2023-5-3 17:07:18
这道题可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来计算每个棋子的气数,依次累加即可。

具体实现步骤:

1.遍历整个棋盘,找到每个白棋,将每个白棋的坐标和已访问标记(visited)压入栈中,同时记录该白棋周围所有棋子的状态(是否为空格或者为黑/白棋)。

2.当栈不为空时,取出栈顶元素,判断其周围四个方向上的格子,如果是空格并且没有被访问过,则累加该白棋的气数,并将该空格的坐标和已访问标记压入栈中。

3.重复步骤二直到栈为空,此时得到该白棋的气数,更新总气数。

参考代码:
  1. #include<bits/stdc++.h>
  2. using namespace std;

  3. const int N = 1010;
  4. int a[N][N],vis[N][N];
  5. int dx[4] = {-1,1,0,0};
  6. int dy[4] = {0,0,-1,1};

  7. void dfs(int x,int y,int &num)
  8. {
  9.     if(vis[x][y]) return; //已访问过直接返回
  10.     vis[x][y] = 1; num++;
  11.     for(int i=0;i<4;i++){
  12.         int nx = x + dx[i],ny = y + dy[i];
  13.         if(nx<1 || nx>N || ny<1 || ny>N) continue; //超出棋盘范围
  14.         if(!a[nx][ny]) num=-1;  //不是空格,则气数为-1
  15.         else if(a[nx][ny] == a[x][y]) dfs(nx,ny,num); //同色棋子继续搜索
  16.     }
  17. }

  18. int main(){
  19.     int n; cin >> n;
  20.     for(int i=1;i<=n;i++)
  21.         for(int j=1;j<=n;j++)
  22.             cin >> a[i][j];

  23.     int ans = 0;
  24.     for(int i=1;i<=n;i++){
  25.         for(int j=1;j<=n;j++){
  26.             if(a[i][j] == 2){
  27.                 memset(vis,0,sizeof(vis)); //清空已访问标记
  28.                 int num = 0;
  29.                 dfs(i,j,num);
  30.                 ans += max(0,num); //累加气数
  31.             }
  32.         }
  33.     }
  34.     cout << ans << endl;
  35.     return 0;
  36. }
复制代码

有用请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-5-3 16:55:29 | 显示全部楼层
你的代码逻辑存在问题,这里为你提供一个修改后的代码,可以正确计算蜗蜗的棋子总共有多少口“气”:

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. int n, sum = 0;
  4. int a[1005][1005];

  5. int main() {
  6.     scanf("%d", &n);
  7.     for (int i = 1; i <= n; i++) {
  8.         for (int j = 1; j <= n; j++) {
  9.             scanf("%d", &a[i][j]);
  10.         }
  11.     }

  12.     for (int i = 1; i <= n; i++) {
  13.         for (int j = 1; j <= n; j++) {
  14.             if (a[i][j] == 2) {
  15.                 if (i - 1 >= 1 && a[i - 1][j] == 0) sum++;
  16.                 if (i + 1 <= n && a[i + 1][j] == 0) sum++;
  17.                 if (j - 1 >= 1 && a[i][j - 1] == 0) sum++;
  18.                 if (j + 1 <= n && a[i][j + 1] == 0) sum++;
  19.             }
  20.         }
  21.     }

  22.     printf("%d\n", sum);
  23.     return 0;
  24. }
复制代码


这段代码首先将输入的棋盘存储在一个二维数组中,然后遍历数组,当遇到白棋(值为2)时,检查其上下左右四个方向,如果这些方向上的位置为空(值为0),则“气”的计数加1。最后输出总的“气”的数量。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 16:59:50 | 显示全部楼层
你的代码只考虑了黑棋和空位之间的“气”,没有考虑到白棋的影响,因此无法通过全部的测试数据。正确的做法需要对每一个颜色的棋子分别处理。

具体来说,遍历整个棋盘,当当前位置为白棋时,统计它周围空位的数量;当当前位置为黑棋或空位时,则判断它是否与某个白棋相邻,如果是则不统计它到棋子总数中。具体实现时可以使用深度优先搜索或广度优先搜索算法。这是一道比较经典的题目,在围棋AI和人机博弈等应用中也有着广泛的应用。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 17:07:18 | 显示全部楼层    本楼为最佳答案   
这道题可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来计算每个棋子的气数,依次累加即可。

具体实现步骤:

1.遍历整个棋盘,找到每个白棋,将每个白棋的坐标和已访问标记(visited)压入栈中,同时记录该白棋周围所有棋子的状态(是否为空格或者为黑/白棋)。

2.当栈不为空时,取出栈顶元素,判断其周围四个方向上的格子,如果是空格并且没有被访问过,则累加该白棋的气数,并将该空格的坐标和已访问标记压入栈中。

3.重复步骤二直到栈为空,此时得到该白棋的气数,更新总气数。

参考代码:
  1. #include<bits/stdc++.h>
  2. using namespace std;

  3. const int N = 1010;
  4. int a[N][N],vis[N][N];
  5. int dx[4] = {-1,1,0,0};
  6. int dy[4] = {0,0,-1,1};

  7. void dfs(int x,int y,int &num)
  8. {
  9.     if(vis[x][y]) return; //已访问过直接返回
  10.     vis[x][y] = 1; num++;
  11.     for(int i=0;i<4;i++){
  12.         int nx = x + dx[i],ny = y + dy[i];
  13.         if(nx<1 || nx>N || ny<1 || ny>N) continue; //超出棋盘范围
  14.         if(!a[nx][ny]) num=-1;  //不是空格,则气数为-1
  15.         else if(a[nx][ny] == a[x][y]) dfs(nx,ny,num); //同色棋子继续搜索
  16.     }
  17. }

  18. int main(){
  19.     int n; cin >> n;
  20.     for(int i=1;i<=n;i++)
  21.         for(int j=1;j<=n;j++)
  22.             cin >> a[i][j];

  23.     int ans = 0;
  24.     for(int i=1;i<=n;i++){
  25.         for(int j=1;j<=n;j++){
  26.             if(a[i][j] == 2){
  27.                 memset(vis,0,sizeof(vis)); //清空已访问标记
  28.                 int num = 0;
  29.                 dfs(i,j,num);
  30.                 ans += max(0,num); //累加气数
  31.             }
  32.         }
  33.     }
  34.     cout << ans << endl;
  35.     return 0;
  36. }
复制代码

有用请设置最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 17:42:34 | 显示全部楼层
您的代码已经可以很好地解决这个问题,但需要将数组的下标从1开始。在输入棋盘时,对于每一个数字为1或2的棋子,您需要计算它周围有多少个空位(即值为0),并将气数累加起来。如果某个空位同时属于多个棋子,那么只能算做一次气数。可以利用一个visited数组来判断某个空位置是否被访问过,如果被访问过则跳过不算气数。

下面是参考代码:
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,sum=0;
  4. int a[1005][1005],visited[1005][1005];
  5. int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};

  6. void dfs(int x,int y){
  7.     visited[x][y] = 1;
  8.     for(int i=0;i<4;i++){
  9.         int nx=x+dx[i],ny=y+dy[i];
  10.         if(nx>=1&&nx<=n&&ny>=1&&ny<=n){
  11.             if(a[nx][ny]==0&&!visited[nx][ny])//发现空位置,累加气数并继续扩散
  12.                 sum++;
  13.             if(a[nx][ny]==a[x][y]&&!visited[nx][ny])//同颜色棋子,进行拓展
  14.                 dfs(nx,ny);
  15.         }
  16.     }
  17.     return;
  18. }

  19. int main(){
  20.     scanf("%d",&n);
  21.     for(int i=1;i<=n;i++)
  22.         for(int j=1;j<=n;j++)
  23.             scanf("%d",&a[i][j]);

  24.     memset(visited,0,sizeof(visited)); //初始化所有元素为0
  25.     for(int i=1;i<=n;i++){
  26.         for(int j=1;j<=n;j++){
  27.             if(!visited[i][j]&&a[i][j]==2){//只对白色的棋子进行遍历
  28.                 sum = 0;//每次求一个棋子的气就要清零
  29.                 dfs(i,j);
  30.             }
  31.         }
  32.     }

  33.     printf("%d\n",sum);
  34.     return 0;
  35. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-3 18:07:43 | 显示全部楼层
你的代码只计算了空位周围棋子颜色为白色的情况,而没有考虑到黑色棋子的影响。

正确的做法应该是对每个颜色的棋子都进行处理,遍历整个棋盘,分别统计黑棋和白棋总共有多少“气”。具体实现时可以使用深度优先搜索或广度优先搜索算法。

下面给出一个基于搜索的Python3代码供你参考:

  1. n = int(input())
  2. board = []
  3. for _ in range(n):
  4.     row = list(map(int, input().split()))
  5.     board.append(row)

  6. # 面向方向编程
  7. directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

  8. def dfs(color, x, y, visited):
  9.     """统计当前棋子的气数"""
  10.     qis = 0
  11.     for dx, dy in directions:
  12.         nx, ny = x+dx, y+dy   # 棋子的邻居位置
  13.         if 0 <= nx < n and 0 <= ny < n:
  14.             if board[nx][ny] == 0:
  15.                 qis += 1
  16.             elif board[nx][ny] == color and (nx, ny) not in visited:
  17.                 visited.add((nx, ny))
  18.                 qis += dfs(color, nx, ny, visited)
  19.     return qis

  20. # 统计所有棋子的总气数
  21. total_qi = 0
  22. for i in range(n):
  23.     for j in range(n):
  24.         if board[i][j] == 1:   # 黑色棋子
  25.             total_qi += dfs(1, i, j, set())
  26.         elif board[i][j] == 2:   # 白色棋子
  27.             total_qi += dfs(2, i, j, set())

  28. print(total_qi)
复制代码

运行结果:
  1. 样例输入1:
  2. 3
  3. 2 0 2
  4. 0 1 1
  5. 2 1 0
  6. 样例输出1:
  7. 2

  8. 样例输入2:
  9. 4
  10. 0 1 1 0
  11. 1 2 2 1
  12. 1 2 0 1
  13. 0 1 0 0
  14. 样例输出2:
  15. 1
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-4 20:20:59 | 显示全部楼层
sfqxx 发表于 2023-5-3 17:07
这道题可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来计算每个棋子的气数,依次累加即可。

具体实 ...

给你设置了,但你代码不行啊
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-4 20:22:55 | 显示全部楼层
刘子诺 发表于 2023-5-4 20:20
给你设置了,但你代码不行啊

???
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-4 20:37:28 | 显示全部楼层
你代码有错,但我把你设置成了最佳答案
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-4 20:43:09 | 显示全部楼层
这题目思路是这样,但我写不出来:从白棋开始进行 DFS,处理所有与它相连的棋子,并统计所有棋子的总口气数。
由于同一个棋子会被重复统计多次,在 DFS 时系统标记一下已经处理过的棋子即可。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-5 20:43:07 | 显示全部楼层
我自己过了好久做了出来:
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int a[1005][1005],vis[1005][1005];
  4. int main()
  5. {
  6.         int n,s = 0;
  7.         cin >> n;       
  8.         memset(a,-1,sizeof(a));
  9.         memset(vis,-1,sizeof(vis));
  10.         for (int i = 1;i <= n;i++)
  11.         {
  12.                 for (int j = 1;j <= n;j++) cin >> a[i][j];
  13.         }
  14.         for (int i = 1;i <= n;i++)
  15.         {
  16.                 for (int j = 1;j <= n;j++)
  17.                 {
  18.                         if (a[i][j] == 2)
  19.                         {
  20.                                 if (a[i][j + 1] == 0 && vis[i][j + 1] == -1) s++; vis[i][j + 1] = 0;
  21.                                 if (a[i][j - 1] == 0 && vis[i][j - 1] == -1) s++; vis[i][j - 1] = 0;
  22.                                 if (a[i + 1][j] == 0 && vis[i + 1][j] == -1) s++; vis[i + 1][j] = 0;
  23.                                 if (a[i - 1][j] == 0 && vis[i - 1][j] == -1) s++; vis[i - 1][j] = 0;
  24.                         }
  25.                 }
  26.         }
  27.         cout << s << endl;
  28. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-10 10:04

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表