codevs 数字三角形集结
添在前面的一句话:初学DP,若有错误,请指出,不能误人子弟,欢迎大家提出意见.水平不高,博客写的比较粗糙,代码也挺丑,请见谅.
最原始的数字三角形:
题目描述 Description
如图所示的数字三角形,从顶部出发,在每一结点可以选择向左走或得向右走,一直走到底层,要求找出一条路径,使路径上的值最大。
输入描述 Input Description
第一行是数塔层数N(1<=N<=100)。
第二行起,按数塔图形,有一个或多个的整数,表示该层节点的值,共有N行。
输出描述 Output Description
输出最大值。
样例输入 Sample Input
5
13
11 8
12 7 26
6 14 15 8
12 7 13 24 11
样例输出 Sample Output
86
数据范围及提示 Data Size & Hint
思路:因为f[i][j] 从 f[i + 1][j] 或者 f[i + 1][j + 1] 转移过来,但是我们要的是最大路径长度,所以从max(f[i +1][j],f[i + 1][j + 1])是最优解,所以DP转移方程为f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]);
代码:
1 #include <iostream> 2 #include <cstdio> 3 #define X 1007 4 5 int f[X][X]; 6 7 int max(int x,int y){ 8 return x > y ? x : y; 9 } 10 11 inline int read(){ 12 int x = 0,f = 1;char c = getchar(); 13 while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 14 while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} 15 return x * f; 16 } 17 18 int main(){ 19 int n; 20 n = read(); 21 for(int i = 1;i <= n;++ i) 22 for(int j = 1;j <= i;++ j) 23 f[i][j] = read(); 24 for(int i = n - 1;i >= 1;-- i) 25 for(int j = 1;j <= i;++ j) 26 f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]); 27 printf("%d",f[1][1]); 28 }
数字三角形w
思路:根据mod 100这个条件,按照上一个题,已经不满足与最优子结构,所以我们要加一维。
可达性DP,我们开一个bool数组 f[i][j][k],f[i][j][k]表示i行,j列,从下面到k值能不能走通,所以我们就想出DP转移方程了,f[i][j][k] = f[i + 1][j][v] | f[i + 1][j + 1][v];(v = (k + 100 - a[i][j] %100) % 100)(ps:这个地方挺重要的,如果k数值 < a[i][j]的话,就会成为负数,然而他是比a[i][j]要大的,所以我们加上一个100也没有关系,建议这个地方好好领悟.先让a[i][j] % 100可以有效的防a[i][j] > k + 100
代码:
1 #include <iostream> 2 #include <cstdio> 3 #define X 30 4 5 int a[X][X]; 6 bool f[X][X][101];//f[i][j][k] i 表示 第i行 j表示第j列 k表示上面的路径%100到k这个值 bool型数组,能到k值为1,到不了为0 7 8 int max(int x,int y){ 9 return x > y ? x : y; 10 }//max函数,我没用using namespace std 11 12 inline int read(){ 13 int x = 0,f = 1;char c = getchar(); 14 while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 15 while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} 16 return x * f; 17 }//快读 不解释 18 19 int main(){ 20 int n,ans = 0;//n 如题 有n层的数字三角形 21 n = read(); 22 for(int i = 1;i <= n;++ i) 23 for(int j = 1;j <= i;++ j) 24 a[i][j] = read();//读入三角形 25 for(int i = 1;i <= n;++ i)f[n][i][((a[n][i] % 100) + 100) % 100] = true;//在最下面一层,不会有人转移到他 26 //所以这是初始条件,a[n][i] % 100 这个值会到达,所以标记为true 27 for(int i = n - 1;i >= 1;-- i){ 28 for(int j = 1;j <= i;++ j){ 29 for(int k = 0;k <= 99;++ k){ 30 int v = (k - (a[i][j] %100) + 100) % 100; 31 f[i][j][k] = f[i + 1][j][v] | f[i + 1][j + 1][v]; 32 } 33 } 34 }//核心代码,根据条件很容易得到DP转移方程 f[i][j][k] = f[i + 1][j] [(k - a[i][j]) % 100] | f[i + 1][j + 1][(k - a[i][j]) % 100]; 35 for(int i = 99;i >= 0;-- i) 36 if(f[1][1][i]){ans = i;break;}//从后往前推,如果这个到达了这个i值,直接break就好. 37 printf("%d",ans); 38 }
数字三角形ww
题目描述 Description
数字三角形必须经过某一个点,使之走的路程和最大
输入描述 Input Description
第1行n,表示n行
第2到n+1行为每个的权值
程序必须经过n div 2,n div 2这个点
输出描述 Output Description
最大值
样例输入 Sample Input
View Code
#include <iostream> #include <cstdio> #define X 30 int f[X][X]; inline int read(){ int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} return x * f; } int max(int x,int y){ return x > y ? x : y; } int main(){ int n = read(),x; for(int i = 1;i <= n;++ i) for(int j = 1;j <= i;++ j) f[i][j] = read(); for(int i = 1;i < n / 2;++ i)f[n/2][i] = -0x3f3f3f3f; for(int i = n - 1;i >= 1;-- i){ for(int j = 1;j <= i;++ j){ f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]); } } printf("%d",f[1][1]); }
2
1
1 1
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
n <=25
思路:只能走f[n / 2][n / 2]这条路,我们就好在n / 2这一行的除了f[n / 2][n / 2]全部设成最小值就可以了.
代码:
1 #include <iostream> 2 #include <cstdio> 3 #define X 30 4 5 int f[X][X]; 6 7 inline int read(){ 8 int x = 0,f = 1;char c = getchar(); 9 while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 10 while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} 11 return x * f; 12 } 13 14 int max(int x,int y){ 15 return x > y ? x : y; 16 } 17 18 int main(){ 19 int n = read(),x; 20 for(int i = 1;i <= n;++ i) 21 for(int j = 1;j <= i;++ j) 22 f[i][j] = read(); 23 for(int i = 1;i < n / 2;++ i)f[n/2][i] = -0x3f3f3f3f; 24 for(int i = n - 1;i >= 1;-- i){ 25 for(int j = 1;j <= i;++ j){ 26 f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]); 27 } 28 } 29 printf("%d",f[1][1]); 30 }
数字三角形WWW:
题目描述 Description
数字三角形必须经过某一个点,使之走的路程和最大
输入描述 Input Description
第1行n,表示n行
第2到n+1行为每个的权值
第n+2行为两个数x,y表示必须经过的点
输出描述 Output Description
最大值
样例输入 Sample Input
2
1
1 1
1 1
样例输出 Sample Output
2
数据范围及提示 Data Size & Hint
n<=25
思路:同上一题差不多,就是将n / 2那一行改成x,然后特判一下y位置就好了,不多说,上代码.
代码:
1 #include <iostream> 2 #include <cstdio> 3 #define X 30 4 5 int f[X][X]; 6 7 inline int read(){ 8 int x = 0,f = 1;char c = getchar(); 9 while(c < '0' || c > '9'){if(c == '-')f = -1;c = getchar();} 10 while(c >= '0' && c <= '9'){x = x * 10 + c - '0';c = getchar();} 11 return x * f; 12 } 13 14 int max(int x,int y){ 15 return x > y ? x : y; 16 } 17 18 int main(){ 19 int n = read(),x,y,tmp; 20 for(int i = 1;i <= n;++ i) 21 for(int j = 1;j <= i;++ j) 22 f[i][j] = read(); 23 x = read(),y = read(); 24 tmp = f[x][y]; 25 for(int i = 1;i <= x;++ i)f[x][i] = -0x3f3f3f3f; 26 f[x][y] = tmp; 27 for(int i = n - 1;i >= 1;-- i){ 28 for(int j = 1;j <= i;++ j){ 29 f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]); 30 } 31 } 32 printf("%d",f[1][1]); 33 }