C++ 数字三角形(最最最基础的DP)

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];  
}

多简单。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘉定世外的JinJiayang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值