题目
1219.黄金矿工
题目大意
你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n
的网格 grid
进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0
。
为了使收益最大化,矿工需要按以下规则来开采黄金:
- 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
- 矿工每次可以从当前位置向上下左右四个方向走。
- 每个单元格只能被开采(进入)一次。
- 不得开采(进入)黄金数目为
0
的单元格。 - 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。
样例
数据规模
思路
设 n n n为网格的行数, m m m为网格的列数,并且由数据可以发现 1 < = n , m < = 15 1<=n,m<=15 1<=n,m<=15。那么可以直接考虑回溯算法。只要 g r i d [ i ] [ j ] > 0 grid[i][j]>0 grid[i][j]>0就说明它可以作为起点,然后开始 d f s + 回 溯 dfs+回溯 dfs+回溯。枚举所有的路径,并且每次更新 a n s = m a x ( a n s , w ) ans=max(ans,w) ans=max(ans,w)。每次 d f s dfs dfs的步骤:
- 由 d f s dfs dfs传入的参数 w w w来更新答案 a n s ans ans,最大化 a n s ans ans。
- 枚举下一个位置 ( n e x , n e y ) (nex,ney) (nex,ney),可以走上下左右四个方向。保证下一个位置之前没有到达过( v i s vis vis没有被标记过)并且 g r i d [ n e x ] [ n e y ] > 0 grid[nex][ney]>0 grid[nex][ney]>0
- d f s dfs dfs之后进行回溯, v i s vis vis标记取消。
代码
class Solution {
public:
int ans=0,n,m;
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int vis[20][20];
void dfs(int x,int y,int w,vector<vector<int>>& grid){
ans=max(ans,w);
for(int i=0;i<4;i++){
int nex=x+dx[i],ney=y+dy[i];
if(nex>=0&&nex<=n-1&&ney>=0&&ney<=m-1&&grid[nex][ney]&&!vis[nex][ney]){
vis[nex][ney]=1;
dfs(nex,ney,w+grid[nex][ney],grid);
vis[nex][ney]=0;
}
}
}
int getMaximumGold(vector<vector<int>>& grid) {
n=grid.size(),m=grid[0].size();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j])
vis[i][j]=1;
dfs(i,j,grid[i][j],grid);
vis[i][j]=0;
}
}
return ans;
}
};