首页 > 其他分享 >数塔

数塔

时间:2023-07-22 14:34:19浏览次数:32  
标签:return 数塔 int max t1 read find

1258:【例9.2】数字金字塔

分析1:
从顶层到底层,面临n-1次决策。向左还是向下?n-1个决策构成一个从顶到底的路径。共有2n-1 条路径,我们的任务是从这些路径中选一条,使得经过的数字之和最大。

n-1次决策可以用长度为n-1的01串表示。

我们穷举所有01串,计算每条路径的和,打擂台求最大。

但是当n很大时,穷举次数太多,导致超时。所以我们在不超时的情况下判断尽可能多的01串,以争取得到最大值。

# include <bits/stdc++.h>
/*
5
13
11 8
12 7  26
6  14 15 8
12 7  13 24 11

86
*/

using namespace std;
const int N=1010;
int n,t,s,a[N][N],maxV=0;

void read(){
    cin>>n;
    for (int i=1;i<=n;i++) 
        for(int j=1;j<=i;j++)
            cin>>a[i][j];
}
int find(unsigned long int t){
    int x=1,y=1;
    int s=a[x][y];
    for(int c=1;c<n;c++){
        int fx=t&1;
        x++;y+=fx;
        s+=a[x][y]; 
        //cout<<x<<" "<<y<<" "<<a[x][y]<<endl;
        t=t>>1;
    }
    return s;       
    
}

int main(){
    read();    
    srand(time(nullptr));    
    int T=1000000;
    while(T--){
        unsigned long int t= rand()*rand();//产生一个大的随机数t,用它的2进制值表示一个方案 
        //cout<<t<<endl;
        int m=find(t);
        if(m>maxV) maxV=m;
    }        
   cout<<maxV<<endl;


    return 0;
}

分析2:

用f(1,1) 表示从1,1出发时获得的最大和,

f(1,1)=a[1][1]+max(f(2,1),f(2,2))

f(2,1)=a[2][1]+max(f(3,1),f(3,2))

f(2,2)=a[2][2]+max(f(3,2),f(3,3))

所以一般式为:

f(i,j)=a[i][j]+max(f(i+1,j),f(i+1,j+1))   (i<n)

f(i,j)=a[i][j]   (i=n)

于是我们可以用深搜。

# include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,a[N][N],s[N][N];

void read(){
    cin>>n;
    for (int i=1;i<=n;i++) 
        for(int j=1;j<=i;j++)
            cin>>a[i][j];
}
int find(int x,int y){    
    if(x==n) return a[n][y];        
    int t1=find(x+1,y);
    int t2=find(x+1,y+1);        
    return a[x][y]+max(t1,t2);    
}
int main(){    
    read();        
    cout<<find(1,1)<<endl;
    return 0;
}

分析3:发现有重复计算,譬如:

f(2,1)=a[2][1]+max(f(3,1),f(3,2))    

f(2,2)=a[2][2]+max(f(3,2),f(3,3))

他们都要算 f(3,2),我们可以记录一下这些值,下次遇到时可以直接调用。

所以我们增加一个数组,记录这些值。这就是记忆化搜索了。这是几乎可以解决n达1000层的问题了。

# include <bits/stdc++.h>
using namespace std;
const int N=1010;
int n,a[N][N],s[N][N];

void read(){
    cin>>n;
    for (int i=1;i<=n;i++) 
        for(int j=1;j<=i;j++)
            cin>>a[i][j];
}

int find(int x,int y){
    if (s[x][y]!=0) return s[x][y];  
    if(x==n) return a[n][y];
    int t1=find(x+1,y);
    int t2=find(x+1,y+1);
    s[x][y]= a[x][y]+t1;
    if(t2>t1) s[x][y]=a[x][y]+t2;
    return s[x][y];    
}

int main(){
    read();        
    cout<<find(1,1)<<endl;
    return 0;
}

分析4:我们可以从底部往上走,把每个小塔的最大和求出来,这个便是DP:

#include<bits/stdc++.h>
using namespace std;
int a[1010][1010];
int n;
int main()
{
   cin>>n;
   for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++) 
       cin>>a[i][j];
   
   for(int i=n-1;i>0;i--)
     for(int j=1;j<=i;j++)
       a[i][j]+=max(a[i+1][j],a[i+1][j+1]) ;
   
   cout<<a[1][1]; 
    return 0;
}

 

标签:return,数塔,int,max,t1,read,find
From: https://www.cnblogs.com/flatte/p/17573325.html

相关文章

  • hdu2084数塔(DP)
    思路:简单的数塔DP#include<stdio.h>#include<string.h>#include<algorithm>usingnamespacestd;inta[105][105],dp[105][105];intmain(){intt,n,i,j;scanf("%d",&t);while(t--){scanf("%d",......
  • HDU 2084 数塔(动态规划入门)
    传送门中文题就不给大家翻译了(手动滑稽),反正大家都看得懂。这是一道动态规划入门的题目,只需要找出状态转移方程即可。状态方程:dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j])(dp[i][j]表示从第i层第j个数开始搜能得到的最大数)代码如下:#include<cstring>#include<iostream>#include<......
  • (hdu step 3.2.7)免费馅饼(数塔变形:求所能接到馅饼的最大数)
    题目:免费馅饼TimeLimit:2000/1000MS(Java/Others)MemoryLimit:65536/32768K(Java/Others)TotalSubmission(s):1207AcceptedSubmission(s):508 ProblemDescription都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。......