问题:
给定一个由n行数字组成的数字三角形,如下图所示:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大(每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数)。
输入:
第一行是数字三角形的行数,接下来 n 行是数字三角形中的数字。
比如:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
输出:
输出这个最大值。
//递归算法
#include<iostream>
using namespace std;
#define N 1000
int map[N][N];
int n;
int triangle(int x, int y)
{
if (x == n)
return map[x][y];
int l = triangle(x + 1, y);
int r = triangle(x + 1, y + 1);
return map[x][y] + (l > r ? l : r);
}
int main()
{
while (cin >> n)
{
memset(map, 0, sizeof(map));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
cin >> map[i][j];
printf("%d\n", triangle(1, 1));
}
return 0;
}
//动态规划
#include<iostream>
#include<algorithm>
using namespace std;
#define N 1000
int dp[N][N];
int main()
{
int n;
while (cin >> n)
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
cin >> dp[i][j];
for (int i = n - 1; i >= 1; i--)
for (int j = 1; j <= i; j++)
dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]);
printf("%d\n", dp[1][1]);
}
return 0;
}
//记忆化搜索
#include<iostream>
#include<algorithm>
using namespace std;
#define N 1000
int map[N][N],vis[N][N];
int n;
int triangle(int x, int y)
{
if (x == n)
return map[x][y];
if (vis[x][y])
return vis[x][y];
vis[x][y] = max(triangle(x + 1, y),
triangle(x + 1, y + 1)) + map[x][y];
return vis[x][y];
}
int main()
{
while (cin >> n)
{
memset(vis, 0, sizeof(vis));
memset(map, 0, sizeof(map));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
cin >> map[i][j];
printf("%d\n", triangle(1, 1));
}
return 0;
}
//位运算
/*
我们将从每个节点上向左还是向右选择一个数0或1来表示
则从顶点到底边的一次累加过程,就获得一个n-1位的二进制
于是,我们枚举n-1位的二进制数,就能得到2的n次方个不同的和
取其最大值即可
感觉很多类似二选一的类型题,都可以考虑使用位运算
因为与位运算0 1恰好对应
*/
/*
5
1
2 3
4 5 6
7 8 9 2
1 3 5 7 9
因为b是从0开始的,即对应的是全部都向左下走
枚举每一b的二进制数都对应其走法
用穷举思想即可,因为2的n次方包含了所有走法
*/
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100
int map[N][N];
int n,Max,s,b;
void triangle()
{
int i, j, s = 0;
int t = 1 << (n - 1);
for (i = j = 1; i <= n; i++)
{
if (b&t) //如果b&t的值为1 就是向右
j++;
s += map[i][j];
t = t>> 1; //n>>=1 中的>>=意思是先将变量n的各个二进制位顺序右移1位,
//最高位补二进制0,然后将这个结果再复制给n。
}
Max = max(Max, s);
}
int main()
{
int lim;
while (cin >> n)
{
memset(map, 0, sizeof(map));
Max = 0;
lim = 1 << (n-1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
cin >> map[i][j];
for ( b= 0; b < lim; b++)
triangle();
printf("%d\n",Max);
}
return 0;
}
//深度优先搜索
#include<iostream>
#include<algorithm>
using namespace std;
#define N 1000
int map[N][N], vis[N];
int n,Max,s;
void dfs(int x, int y)
{
int i;
if (x == n)
{
Max = max(Max, s);
return;
}
for (int i = 0; i <= 1; i++)
{
s += map[x + 1][i+y];
dfs(x + 1, i+y);
s -= map[x + 1][i+y];
}
}
int main()
{
while (cin >> n)
{
memset(vis, 0, sizeof(vis));
memset(map, 0, sizeof(map));
Max = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
cin >> map[i][j];
s = map[1][1];
dfs(1, 1);
printf("%d\n", Max);
}
return 0;
}