P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题解
下面我们将要分析一道十分著名的题目:数字三角形
下面请选择你读完题的感受:
A骗分 B暴力搜索 C贪心 D动规
骗分
A:
#include<bits/stdc++.h>
using namespace std;
int main()
{
cout << 10;
return 0;
}
确实够搞笑的
暴搜
B
#include <bits/stdc++.h>
#define fp(i,l,r) for(register int i=(l);i<=(r);i++)
#define fd(i,r,l) for(register int i=(r);i>=(l);i--)
using namespace std;
int ans;
int n;
int a[1002][1002];
int _count=0;
int _max(int a,int b){
if(a>b){
return a;
}
return b;
}
int search(int x,int y){
_count+=a[x][y];
if(x==n){
ans=_max(_ans,_count);
}
else{
search(x+1,y);
search(x+1,y+1);
}
_count-=a[x][y];
}
int main(){
scanf("%d",&n);
fp(i,1,n){
fp(j,1,i){
scanf("%d",&a[i][j]);
}
}
search(1, 1);
cout << ans;
return 0;
}
复杂度呈指数级增长,过高
贪心
C
#include <bits/stdc++.h>
#define fp(i,l,r) for(register int i=(l);i<=(r);i++)
#define fd(i,r,l) for(register int i=(r);i>=(l);i--)
using namespace std;
int ans;
int n;
int a[1000][1000];
int _count=0;
int _max(int a,int b){
if(a>b){
return a;
}
return b;
}
int yh(int x,int y){
if(x==n){
return 0;
}
ans+=_max(a[x+1][y],a[x+1][y+1]);
if(_max(a[x+1][y],a[x+1][y+1])==a[x+1][y]){
yh(x+1,y);
}
else{
yh(x+1,y+1);
}
}
int main(){
scanf("%d",&n);
fp(i,1,n){
fp(j,1,i){
scanf("%d",&a[i][j]);
}
}
ans=a[1][1];
yh(1, 1);
printf("%d",_ans);
return 0;
}
鼠目寸光,不可行
动规
D
动规分析
动规的基础:
最优子结构
无后效性
动规的重点:
状态转移方程
我们如果从上往下推,又变成了dfs+剪枝
从下往上推才是今天的重点
状态转移方程
很明显,第n层的数据最优取决于第n+1层最优
因此,状态转移方程为
DP[x][y] = max(DP[x+1][y], DP[x+1][y+1]) + VALUES[x][y]
DP[x][y]:在第x行第y列上的最优解
VALUES[x][y]:在第x行第y列上的数据
翻译成人类语就是:
第x行y列的最优解(dpxy)是第x+1行第y列的解(dpx+1y)和第x+1行第y+1列的解(dpx+1y+1)最大值(max)加上(+)第x行第y列的值(valuesxy)
确定边界:
DP[end][i] = VALUES[end][i]
结果即DP[1][1]
最终代码
记忆化搜索
#include<bits/stdc++.h>
using namespace std;
int n;
int vls[1001][1001];
int come[1001][1001];
int best[1001][1001];
int result = -1;
int dfs(int x, int y, int time)
{
if(y > x) return 0;
if(time > best[x][y]) best[x][y] = time;
else return 0;
int now = time+vls[x][y];
cout << x << ' ' << y << ' ' << now << endl;
if(x == n)
{
if(now > result) result = now;
return 0;
}
dfs(x+1, y, now);
dfs(x+1, y+1, now);
}
int main()
{
memset(best, 0x3f, sizeof(best));
cin >> n;
for(int i=1; i<=n; i++) for(int j=1; j<=i; j++) scanf("%d", &vls[i][j]);
for(int i=1; i<=n; i++) best[n][i] = vls[n][i];
for(int i=n-1; i>=1; i--) for(int j=1; j<=i; j++) best[i][j] = max(best[i+1][j], best[i+1][j+1]) + vls[i][j];
cout << best[1][1];
return 0;
}
多复杂啊。。。
动态规划
#include<bits/stdc++.h>
using namespace std;
int vls[1002][1002];
int dp[1002][1002];
int main()
{
int n;
cin >> n;
for(int i=1; i<=n; i++) for(int j=1; j<=i; j++) cin >> vls[i][j];
for(int i=1; i<=n; i++) dp[n][i] = vls[n][i];
for(int i=n-1; i>0; i--) for(int j=1; j<=i; j++) dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + vls[i][j];
cout << dp[1][1];
}
多简单。。。