P1123 取数游戏(洛谷)

题目描述

一个N×M的由非负整数构成的数字矩阵,你需要在其中取出若干个数字,使得取出的任意两个数字不相邻(若一个数字在另外一个数字相邻8个格子中的一个即认为这两个数字相邻),求取出数字和最大是多少。

输入格式

第1行有一个正整数T,表示了有T组数据。

对于每一组数据,第一行有两个正整数N和M,表示了数字矩阵为N行M列。

接下来N行,每行M个非负整数,描述了这个数字矩阵。

输出格式

T行,每行一个非负整数,输出所求得的答案。

输入输出样例

输入 #1
3
4 4
67 75 63 10
29 29 92 14
21 68 71 56
8 67 91 25
2 3
87 70 85
10 3 17
3 3
1 1 1
1 99 1
1 1 1

输出 #1

271
172
99

解题思路:

  直接用dfs是会TLE的(因为我直接用只跑通了4个测试样例),平常dfs中我们会使用for循环来改变要访问元素四个上下左右的位置,但是在此题中,dfs中套上for就会TLE。因此需要有一个更高效的移动方法:在此处,我们默认每次移动都是y+1;当时当y>m超过当前列数时,我们设置y=1(第一列)和x+1。由此看来,这个移动是固定的,而且我们可以知道下一步它的具体位置,在此方法中能确保所有位置都遍历到。移动的终止条件是x>n超过行数时return。

  我们对于每一个位置都有取和不取值两种情况(这样就涵盖了所有情况组合),从第一个位置搜索:取和不取先各来一次dfs。在dfs中,到达某个元素时,他有两种状态:能取和不能取,对于能取的:则取一次,标记为1表示取过,在dfs; 然后回溯标记0,再不取其值直接dfs,对于不能取的(表示周围元素有被取过的): 直接dfs。

  注意点:在这里不应该找到某个位置,取其值后就立即把它周围的元素给标记了,这样会带来很高的复杂度。dfs(x,y,sum)表示的是访问到xy位置时的状态,而且此时是否相加的情况也处理好了。因此下面代码的思路应该是访问到某个元素后,先找到它下一个要移动的位置,再去判断该位置是否能取其值,若能则接下来有两个dfs,若不能接下来有一个dfs。

 

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 int n,m;
 6 int a[10][10]={0};
 7 int map[10][10]={0};
 8 
 9 int maxx=0;    //用来存放最大值
10 
11 
12 void dfs(int x,int y,int sum){        //x代表行,y代表列  sum当前值
13  
14     maxx=max(maxx,sum);
15     
16     //有规则的移动 列数加1直到列数最大时,此时列数变为1,行数++
17     int my=y+1;
18     int mx=x;
19     if(my>m){
20         my=1;
21         mx=x+1;
22     } 
23     if(mx>n)    return;        //递归终止条件 
24     
25     
26     if(!map[mx-1][my-1]&&!map[mx][my-1]&&!map[mx+1][my-1]&&!map[mx-1][my]&&!map[mx+1][my]&&!map[mx-1][my+1]&&!map[mx][my+1]&&!map[mx+1][my+1]){
27         map[mx][my]=1;
28         dfs(mx,my,sum+a[mx][my]);
29         map[mx][my]=0;
30     }
31     
32     dfs(mx,my,sum);
33     
34     return;
35 }
36 int main(){
37     int t;
38     cin>>t;
39     
40     for(int i=1;i<=t;i++){
41         n=m=0;
42         cin>>n>>m;
43         memset(a,0,sizeof(a));
44         maxx=0;
45         
46         for(int i=1;i<=n;i++){
47             for(int j=1;j<=m;j++){
48                 cin>>a[i][j];
49             }
50         } 
51 
52         memset(map,0,sizeof(map));
53         dfs(1,1,0);  //代表取当前第一个数
54         memset(map,0,sizeof(map));
55         map[1][1]=1;
56         dfs(1,1,a[1][1]);  //代表不取当前第一个数
57         cout<<maxx<<endl;
58         
59     }
60     return 0;
61 }

 

 
posted @ 2020-03-23 01:50  neverstopcoding  阅读(490)  评论(0编辑  收藏  举报