蓝桥杯小怂爱水洼

项目场景:

问题描述 小怂喜欢收集水洼中的水,他每到一个水量不为零的小水洼中就会收集里面的所有水。 小怂去到了一个大小为N×M的水洼上,水洼上的每一块小水洼水量为ai,j(i∈[1,n],j∈[1,m])。假设小怂的起始点是(1,1),他可以移动无数次,每次移动只能移动到当前水洼上下左右四个方向的相邻小水洼上,并且需要满足相邻小水洼水量大于0,即如果新的小水洼水量为零,小怂就不能走到这个小水洼上。特别地,小怂可以重复走到某块小水洼,但是小水洼中的水只能被收集一次;如果起始点的水洼中有水,他会收集那些水。 值得注意的是:每块上下左右相连且水量不为0的小水洼会合成一块大水洼,小怂每到一块新的大水洼,他之前收集到的水量会变为0。 求解小怂在大水洼中可以收集到的最大水量。 输入格式 第一行是两个整数N,M,分别表示行数、列数。 接下来N行,每行包含M个整数,每个整数表示当前位置的小水洼的水量。 数据范围保证:1≤N,M≤100,1≤aij≤10⁶,(数据不保证起始点不为0)。 输出格式 输出共1行,一个整数,表示小怂在水洼中可以收集到的最大水量。样例输入 33 120 340 005 样例输出 10 样例解释 由题意得,样例中有两个大水洼。 第一个大水洼由(1,1),(1,2),(2,1),(2,2)四个小水洼组成, 水量总和为10。 第二个大水洼由(3,3)一个小水洼组成,水量总和为5。因此小怂在大水洼中可以获得的最大水量是10。


错误代码:

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N][N];
int ans=0,cnt=0;
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
int n,m;
void dfs(int x,int y)
{
  if(x<1||x>n||y<1||y>m) return;
  for(int i=0;i<4;i++)
  {
    int aa=x+dx[i],b=y+dy[i];
    if(aa<1||aa>n||b<1||b>m) continue;
    if(a[aa][b]==0) continue;
    cnt+=a[aa][b];
    a[aa][b]=0;
    dfs(aa,b);
  }
}
int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  cin>>n>>m;
  for(int i=1;i<=n;i++)
  {
    for(int j=1;j<=m;j++)
    {
      cin>>a[i][j];
    }
  }
  for(int i=1;i<=n;i++)
  {
    for(int j=1;j<=m;j++)
    {
      if(a[i][j]==0) continue;
      dfs(i,j);
      ans=max(ans,cnt);
      cnt=0;
    }
  }
  cout<<ans<<'\n';
  return 0;
}

原因分析:

1.在使用dfs时一开始的点没有清除掉(标记掉),会重复计算进入dfs的点,导致结果出错

2.a[i][j]的范围是1~1e6,所以ans和cnt可能会超出int范围


解决方案:

1.在进入dfs前把a[i][j]清除为0,同时在cnt加上

2.using ll = longlong

#include<bits/stdc++.h>
using namespace std;
using ll = long long;//防止超出int范围
const int N = 105;
int a[N][N];
ll ans = 0, cnt = 0;//ans为每个大水洼水量和的比较,cnt记录每个大水洼的水量和
int dx[] = { 1,0,-1,0 };//表示x左右
int dy[] = { 0,1,0,-1 };//表示y左右
int n, m;
void dfs(int x, int y)
{
    if (x<1 || x>n || y<1 || y>m) return;//剪枝
    for (int i = 0; i < 4; i++)//上下左右的情况
    {
        int aa = x + dx[i], b = y + dy[i];
        if (aa<1 || aa>n || b<1 || b>m) continue;
        if (a[aa][b] == 0) continue;
        cnt += 1ll * a[aa][b];//变为long long值
        a[aa][b] = 0;
        dfs(aa, b);
    }
}
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> a[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            if (a[i][j] == 0) continue;
            cnt += 1ll * a[i][j];//在进入前加上该点
            a[i][j] = 0;//清除该店
            dfs(i, j);
            ans = max(ans, cnt);//比较大小
            cnt = 0;//清零重新记录
        }
    }
    cout << ans << '\n';
    return 0;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值