项目场景:
问题描述 小怂喜欢收集水洼中的水,他每到一个水量不为零的小水洼中就会收集里面的所有水。 小怂去到了一个大小为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;
}