状态是从左边或者上面转移过来
数字三角型模板
摘花生
//AcWing 1015. 摘花生
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100 + 10;
int n, m;
int w[N][N], f[N][N];
int main ()
{
int T;//T组数据
scanf("%d", &T);
while (T -- )
{
scanf("%d%d", &n, &m);//每组数据有n行m列,原点是左上角
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &w[i][j]);//初始化权重数组
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
f[i][j] = max(f[i - 1][j], f[i][j - 1]) + w[i][j];//递推公式,这里一开始没输出,没包括max的头文件,但是不知道为什么不CE
printf("%d\n", f[n][m]);
}
return 0;
}
最低通行费
这题没有明确给出只能向右或者向下走,但是给出了一个提示——在2N - 1步内走到终点
#include<iostream>
using namespace std;
const int N=110,INF=0x3f3f3f3f;
int f[N][N],w[N][N];
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n; i ++ )
for(int j = 1;j <= n;j ++ )
cin >> w[i][j];
//因为这题要求求最小值,则初始化周围的数为正无穷
for(int i = 2; i <= n; i ++ ) //保证f[1][1] = w[1][1];
{
f[0][i] = INF;
f[i][0] = INF;
}
// for(int i = 2; i <= n; i ++ ) //这样不行,因为f[1][1]状态会从f[0][1]和f[1][0]递推出来,f[0][1]和f[1][0]都是 INF
// {
// f[0][i] = INF;
// f[i][0] = INF;
// }
// f[1][1] = w[1][1];//即使加上这个也无法保证f[1][1] = w[1][1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i-1][j],f[i][j-1])+w[i][j];//从左边或者上边走的最小值
cout<<f[n][n];
return 0;
}
方格取数
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 11;
int n;
int w[N][N], f[2 * N][N][N];
int main ()
{
cin >> n;
int a, b, c;
while (cin >> a >> b >> c, a || b || c) w[a][b] = c;
for (int k = 2; k <= 2 * n; k ++ )//注意遍历顺序,先遍历k
for (int i1 = 1; i1 <= n; i1 ++)
for (int i2 = 1; i2 <= n; i2 ++ )
{
int j1 = k - i1, j2 = k - i2; //关键,;利用i+j=k将两次走过的路简化为一个三维数组,
if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
{
int t = w[i1][j1];
int &x = f[k][i1][i2];
if (i1 != i2) t += w[i2][j2];//如果两者没重复,再加上i2,j2
x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
x = max(x, f[k - 1][i1 - 1][i2] + t);
x = max(x, f[k - 1][i1][i2 - 1] + t);
x = max(x, f[k - 1][i1][i2] + t);
}
}
cout << f[2 * n][n][n];
return 0;
}
传纸条
和上题一摸一样,改几个数据就行了
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 51;
int n, m;
int w[N][N], f[2 * N][N][N];
int main ()
{
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> w[i][j];
for (int k = 2; k <= n + m; k ++ )//注意遍历顺序,先遍历k
for (int i1 = 1; i1 <= n; i1 ++)
for (int i2 = 1; i2 <= n; i2 ++ )
{
int j1 = k - i1, j2 = k - i2; //关键,;利用i+j=k将两次走过的路简化为一个三维数组,
if (j1 >= 1 && j1 <= m && j2 >= 1 && j2 <= m)
{
int t = w[i1][j1];
int &x = f[k][i1][i2];
if (i1 != i2) t += w[i2][j2];//如果两者没重复,再加上i2,j2
x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
x = max(x, f[k - 1][i1 - 1][i2] + t);
x = max(x, f[k - 1][i1][i2 - 1] + t);
x = max(x, f[k - 1][i1][i2] + t);
}
}
cout << f[n + m][n][n];
return 0;
}