微信扫一扫打赏支持

dp4--codeVs1043 方格取数

dp4--codeVs1043 方格取数

一、心得

 

二、题目

1043 方格取数

 

2000年NOIP全国联赛提高组

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
 
题目描述 Description

设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

 

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

 

输入描述 Input Description

输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出描述 Output Description

    只需输出一个整数,表示2条路径上取得的最大的和。

样例输入 Sample Input

      8

      2  3  13

      2  6   6

      3  5   7

      4  4  14

      5  2  21

      5  6   4

      6 3  15

      7 2  14

      0 0  0

样例输出 Sample Output

      67

数据范围及提示 Data Size & Hint
如描述

三、分析

* codeVs1043方格取数.cpp
* 分析:
* 把这个问题看成两个人同时走就ok了
* 状态:
* f[h1][w1][h2][w2]表示第一个人走到(h1,w1)位置和第二个人走到(h2,w2)位置所取的最大和
* 最终状态:
* f[n][n][n][n]
* 初始状态:
* f[0][0][0][0] (都没走的情况,这就是最初的情况)
* 只可能两个人同时走了或者没走,不可能一个人走了,一个人没走
*
* 状态转移方程:
* 走到(h1,w1),(h2,w2)的四种方式:
* 1、都向下走 f[h1-1][w1][h2-1][w2]
* 2、都向右走 f[h1][w1-1][h2][w2-1]
* 3、第一个人向下,第二个人向右 f[h1-1][w1][h2][w2-1]
* 4、第一个人向右,第二个人向下 f[h1][w1-1][h2-1][w2]
* 用T表示这四种状态里面最优的一个
* T=max(f[h1-1][w1][h2-1][w2],f[h1][w1-1][h2][w2-1],f[h1-1][w1][h2][w2-1],f[h1][w1-1][h2-1][w2])
* 如果(h1,w1)==(h2,w2)
* f[h1][w1][h2][w2]=a[h1][w1]+T
* 如果(h1,w1)!=(h2,w2)
* f[h1][w1][h2][w2]=a[h1][w1]+a[h2][w2]+T

 

四、AC代码

5ms

  1 /*
  2  * codeVs1043方格取数.cpp
  3  * 分析:
  4  * 把这个问题看成两个人同时走就ok了
  5  * 状态:
  6  * f[h1][w1][h2][w2]表示第一个人走到(h1,w1)位置和第二个人走到(h2,w2)位置所取的最大和
  7  * 最终状态:
  8  * f[n][n][n][n]
  9  * 初始状态:
 10  * f[0][0][0][0] (都没走的情况,这就是最初的情况)
 11  * 只可能两个人同时走了或者没走,不可能一个人走了,一个人没走
 12  *
 13  * 状态转移方程:
 14  * 走到(h1,w1),(h2,w2)的四种方式:
 15  * 1、都向下走 f[h1-1][w1][h2-1][w2]
 16  * 2、都向右走 f[h1][w1-1][h2][w2-1]
 17  * 3、第一个人向下,第二个人向右 f[h1-1][w1][h2][w2-1]
 18  * 4、第一个人向右,第二个人向下 f[h1][w1-1][h2-1][w2]
 19  * 用T表示这四种状态里面最优的一个
 20  * T=max(f[h1-1][w1][h2-1][w2],f[h1][w1-1][h2][w2-1],f[h1-1][w1][h2][w2-1],f[h1][w1-1][h2-1][w2])
 21  * 如果(h1,w1)==(h2,w2)
 22  * f[h1][w1][h2][w2]=a[h1][w1]+T
 23  * 如果(h1,w1)!=(h2,w2)
 24  * f[h1][w1][h2][w2]=a[h1][w1]+a[h2][w2]+T
 25  *
 26  */
 27 
 28 #include <iostream>
 29 #include <cstdio>
 30 #define maxn 13
 31 using namespace std;
 32 int n;
 33 int f[maxn][maxn][maxn][maxn];
 34 int a[maxn][maxn];
 35 
 36 void initArr_a() {
 37     for (int i = 1; i < maxn; i++) {
 38         for (int j = 1; j < maxn; j++) {
 39             a[i][j] = 0;
 40         }
 41     }
 42 }
 43 
 44 void readData() {
 45     cin >> n;
 46     int h, w, x;
 47     while (scanf("%d %d %d", &h, &w, &x) == 3) {
 48         bool t1 = h == 0 && w == 0 && x == 0;
 49         if (t1)
 50             break;
 51         a[h][w] = x;
 52     }
 53 }
 54 
 55 void printArr_a() {
 56     for (int i = 1; i <= n; i++) {
 57         for (int j = 1; j <= n; j++) {
 58             printf("%5d", a[i][j]);
 59         }
 60         cout << endl;
 61     }
 62 }
 63 
 64 void initArr_f() {
 65     for (int i1 = 0; i1 <= n; i1++) {
 66         for (int i2 = 0; i2 <= n; i2++) {
 67             for (int i3 = 0; i3 <= n; i3++) {
 68                 for (int i4 = 0; i4 <= n; i4++) {
 69                     f[i1][i2][i3][i4] = 0;
 70                 }
 71             }
 72         }
 73     }
 74     //都没出发的情况
 75     f[0][0][0][0] = 0;
 76 
 77 }
 78 void init() {
 79     initArr_a();
 80     readData();
 81     //printArr_a();
 82     initArr_f();
 83 }
 84 
 85 int max4(int a, int b, int c, int d) {
 86     int tmp1 = max(a, b);
 87     int tmp2 = max(c, d);
 88     return max(tmp1, tmp2);
 89 }
 90 
 91 void dp() {
 92     for (int i1 = 1; i1 <= n; i1++) {
 93         for (int i2 = 1; i2 <= n; i2++) {
 94             for (int i3 = 1; i3 <= n; i3++) {
 95                 for (int i4 = 1; i4 <= n; i4++) {
 96                     int tmp= max4(f[i1-1][i2][i3-1][i4],f[i1][i2-1][i3][i4-1],f[i1-1][i2][i3][i4-1],f[i1][i2-1][i3-1][i4]);
 97                     if(i1==i3&&i2==i4){
 98                         f[i1][i2][i3][i4]=a[i1][i2]+tmp;
 99                     }
100                     else{
101                         f[i1][i2][i3][i4]=a[i1][i2]+a[i3][i4]+tmp;
102                     }
103                 }
104             }
105         }
106     }
107 }
108 
109 void printAns(){
110     cout<<f[n][n][n][n]<<endl;
111 }
112 
113 int main() {
114     //freopen("src/codeVs1043.txt", "r", stdin);
115     init();
116     dp();
117     printAns();
118     return 0;
119 }
120 
121 /*
122  * 注意点
123  * 1、在找初始状态上面还有点问题
124  *         一般是f[i][0],f[0][j],f[0][0],还有一些看题目
125  *         多维也是仿照两维来写状态转移方程
126  * 2、找准初始状态的实际意义,状态转移方程就好写了
127  * 3、向下和向右走正好对应x,y的++
128  */

 

 

 

五、注意点

1、在找初始状态上面还有点问题
       一般是f[i][0],f[0][j],f[0][0],还有一些看题目
       多维也是仿照两维来写状态转移方程
2、找准初始状态的实际意义,状态转移方程就好写了
3、向下和向右走正好对应x,y的++

 

posted @ 2017-08-14 23:28  范仁义  阅读(296)  评论(0编辑  收藏  举报