爬楼梯问题--有n阶台阶,上楼可以一步上1阶,2阶,3阶,计算共有多少种不同的走法

爬楼梯问题--有n阶台阶,上楼可以一步上1阶,2阶,3阶,计算共有多少种不同的走法,第1张

简单的dp问题:

#include

int step[2048];

int p = step;

void foo(int n)

{

if(n > 0) {

if(n > 1) {

p++ = 2;

foo(n-2);

--p;

}

p++ = 1;

foo(n-1);

--p;

} else {

for(int k = step; k != p; ++k)

printf("%d ",k);

putchar('\n');

}

}

int main()

{

foo(5);

}

你可能被题目给出的例子给误导了。题目给出的例子:

4

2 3 5 10

也就是:(2,3) (3,5) (5,10) (10,2),最优解刚好是按顺序的,也就是

4和1,炼出的珠子再和2,接着再和3。

因此,你的程序找最优解的算法,就是枚举从任意一颗珠子开始,一直按一个方向炼制下去。

因为有N个珠子,因此有N中结果,你就从这个N个结果中找一个最大的,作为最优值。

但是,这个算法是不完整的!!!题目并没说一定要按给出顺序,一直炼制下去!你可以任意挑出两个珠子,只要它们的头和尾一样就可以炼制了。

因此实际的炼制方法,远远多于N。设N颗珠子有F(N)种炼制方法,则:

F(N)=NF(N-1),N>=3。且 F(1)=0,F(2)=1。

可以统一成:F(N)=N!/2,N>=2。F(1)=0。

题目的N范围:(4<=N<=100),如果采用暴力枚举的话,F(N)会达到很大的数量级。

你要问的,为什么:

7

23 17 212 113 71 301 33

正确结果:31182687

而我代码所产生的结果是:17489304

就是因为你枚举了N=7种情况,实际有7!/2=2520种情况,远远大于你枚举的范围。

通过上面的分析,可以知道,暴力枚举是行不通的。这题就是要用你提到的DP(动态规划来做的)。

用DP(动态规划)的做法是:

1)设有 N 颗珠子,信息保存在 pearls[N]中

2)energy[i][j] 表示从第 i 颗珠子到第 j 颗珠子能获得的最大能量

初始设置为-1,表示还没有计算出来。

3)当 i==j ,是同一颗珠子,energy[i][j]=0

当 (i+1)%N==j,表示的是两颗相邻的珠子,能获得能量为:

energy[i][j] = pearls[i]pearls[(i+1)%N]pearls[(i+2)%N]

其他情况,在 i,j 之间任意选一个位置 k(i<=k<j)断开,计算:

a) 第 i 颗珠子到第 k 颗珠子的最大能量:energy[i,k],

也就是第 k 颗珠子左边所有珠子的最大能量;

b) 第 k+1 颗珠子到第 j 颗珠子的最大能量:energy[k+1,j],

也就是第 k 颗珠子右边所有珠子的最大能量;

c) 第k可珠子左边和右边计算能量后,各剩下一颗珠子,这两颗珠子获得的能量为:

pearls[i]pearls[k]pearls[(j+1)%N]

a,b,c三部分的能量相加,就是当选择 k 位置断开后,在珠子 i,j直接能获得的最大能量。

如果这个能量比原来的 energy[i][j] 要大,energy[i][j] 就更新为这个能量值。

4) energy[0][N-1]就是题目要求的,使用N颗珠子能获得的最大能量。

用dp的方法,并在每一步记录一下是哪一步转移过来的

倒着找回去就可以了

用C++写了一发,有少许注释,供参考

#include <iostream>

#include <cstdio>

#include <cstring>

#include <vector>

#define MAX(a,b) ((a)>(b)(a):(b));

using namespace std;

struct Point{

int x,y;

Point(int x=0,int y=0):x(x),y(y){}

};

//

//the operator 

struct Operator{

int type;

int to;

Operator(int type=0,int to=0):type(type),to(to){}

/

type    0    No Opeartor

1    Insert to

2    Delete

3    Change ->to 

/

};

//

//new and delete for 2D array

template<class T>

T new_2D_Array(int n,int m){

T res=new T[n];

res[0]=new T[nm];

for(int i=1;i<n;i++)

    res[i]=res[i-1]+m;

return res;

}

template<class T>

void delete_2D_Array(T src){

delete []src[0];

delete []src;

}

//

int get_eu(char i,char j){

    return i==j  0:1;

}

/  dp for min edit distance  /

/  pre means witch status transfor to current status  /

/  op means how to change from pre to current/

int min_Edit_Dis(string s1,string s2,string &res,vector<Operator>&resop,vector<int>&respos){

int ret=0,reti=-1,retj=-1,n=s1size(),m=s2size();

int dp=new_2D_Array<int>(s1size()+1,s2size()+1);

Point pre=new_2D_Array<Point>(s1size()+1,s2size()+1);

Operator op=new_2D_Array<Operator>(s1size()+1,s2size()+1);

for(int i=0;i<n;i++){

for(int j=0;j<m;j++){

dp[i][j]=0;

pre[i][j]=Point(-1,-1);

}

}

    dp[0][0]=0;

    op[0][0]=Operator(0,'!');

for(int i=1;i<=n;i++){

dp[i][0]=i;

    op[i][0]=Operator(2,64);

    pre[i][0]=Point(i-1,0);

}

for(int i=1;i<=m;i++){

dp[0][i]=i;

op[0][i]=Operator(1,s2[i-1]);

pre[0][i]=Point(0,i-1);

}

pre[0][0]=Point(-1,-1);

for(int i=1;i<=n;i++){

for(int j=1;j<=m;j++){

dp[i][j]=dp[i-1][j]+1;

pre[i][j]=Point(i-1,j);

op[i][j]=Operator(2,64);

if(dp[i][j-1]+1<dp[i][j]){

dp[i][j]=dp[i][j-1]+1;

pre[i][j]=Point(i,j-1);

op[i][j]=Operator(1,s2[j-1]);

}

if(dp[i-1][j-1]+get_eu(s1[i-1],s2[j-1])<dp[i][j]){

dp[i][j]=dp[i-1][j-1]+get_eu(s1[i-1],s2[j-1]);

pre[i][j]=Point(i-1,j-1);

if(s1[i-1]==s2[j-1])

op[i][j]=Operator(0,'!');

else

op[i][j]=Operator(3,s2[j-1]);

}

}

}

     

    ret=dp[n][m];

/   print pre op dp

    printf("(%d,%d)\n",reti,retj);

printf(" ");

for(int i=0;i<=m;i++)

if(i==0) printf("         ");

    else printf("%5c    ",s2[i-1]);

printf("\n");

for(int i=0;i<=n;i++){

if(i==0) printf(" ");

else printf("%c",s1[i-1]);

for(int j=0;j<=m;j++){

printf(" (%2d,%2d) ",pre[i][j]x,pre[i][j]y);

}

cout<<endl;

}

printf("(%d,%d)\n",reti,retj);

printf(" ");

for(int i=0;i<=m;i++)

if(i==0) printf("         ");

    else printf("%5c    ",s2[i-1]);

printf("\n");

for(int i=0;i<=n;i++){

if(i==0) printf(" ");

else printf("%c",s1[i-1]);

for(int j=0;j<=m;j++){

printf(" (%2d,%2c) ",op[i][j]type,op[i][j]to);

}

cout<<endl;

}

    printf("  ");

for(int i=0;i<=m;i++) 

if(i==0) printf("    ");

    else printf("%c  ",s2[i-1]);

printf("\n");

for(int i=0;i<=n;i++){

if(i==0) printf("  ");

else printf("%c ",s1[i-1]);

for(int j=0;j<=m;j++){

printf("%2d ",dp[i][j]);

}

cout<<endl;

}

/

resopclear();

resposclear();

int curi=n,curj=m;  

/to get the road (include null op)/

while(curi!=-1){

resoppush_back(op[curi][curj]);

respospush_back(curi-1);

int tmpi=pre[curi][curj]x;

curj=pre[curi][curj]y;

curi=tmpi;

}

return ret;

}

/delete the null op,and get the string of each step/

/Skill:

    Change Form Right to Left,so the index will not change when operator

/

void get_Recoder(string src,vector<Operator>&op,vector<int>&pos,vector<string>&res){

    resclear();

    respush_back(src);

    vector<Operator> tmpop;

    vector<int> tmppos;

    tmpopclear();

    tmpposclear();

    string curs=src;

    char buffer[2]={0,0};

for(int i=0;i<opsize();i++){

Operator curp=op[i];

int curpos=pos[i];

if(curptype==0) continue;

else if(curptype==1){

curs=cursinsert(curpos+1,1,curpto);

respush_back(curs);

}

else if(curptype==2){

curs=curserase(curpos,1);

respush_back(curs);

}

else if(curptype==3){

curs[curpos]=curpto;

respush_back(curs);

}

tmppospush_back(curpos);

tmpoppush_back(curp);

}

opclear();

posclear();

for(int i=0;i<tmppossize();i++){

oppush_back(tmpop[i]);

pospush_back(tmppos[i]);

}

}

/Print the process/

void printRecord(string src,vector<Operator>&op,vector<int>&pos,vector<string>&road){

char operatorList[4][15]={"   GOAL   ","  INSERT  ","  DELETE  ","  CHANGE  "};

int spacesize=6;

for(int i=0;i<roadsize();i++)

spacesize=MAX(spacesize,road[i]size());

for(int i=0;i<spacesize+32;i++)

printf("_");

/

Pos:

k i t t e n

0 1 2 3 4 5 6

/

printf("\n|%-s | pos | operator | form | to |\n|",spacesize,"string");

for(int i=0;i<spacesize;i++)printf("-");

printf("------------------------------|\n");

printf("|%-s |   / |  SOURCE  |  /   | /  |\n",spacesize,srcc_str());

for(int i=0;i<opsize();i++){

string tmps=road[i];

Operator top=op[i];

int tpos=pos[i];

printf("|%-s |%4d |%s|  %c   | %c  |\n",spacesize,tmpsc_str(),tpos+(toptype==1  1:0),operatorList[toptype],(toptype==3 || toptype==2)  src[tpos]:'/',(toptype==3 || toptype==1) topto:('/'));

}

printf("|%-s |   / |  TARGET  |  /   | /  |\n",spacesize,road[roadsize()-1]c_str());

for(int i=0;i<spacesize+32;i++)printf("-");

printf("\nRoad Finished\n");

}

int main(){

string A="kitten";

string B="sitting";

string C;

vector<Operator>op;

vector<int>pos;

vector<string>road;

int res=min_Edit_Dis(A,B,C,op,pos);

printf("The min edit dis is: %d\n",res);

get_Recoder(A,op,pos,road);

printRecord(A,op,pos,road);

return 0;

}

以上就是关于爬楼梯问题--有n阶台阶,上楼可以一步上1阶,2阶,3阶,计算共有多少种不同的走法全部的内容,包括:爬楼梯问题--有n阶台阶,上楼可以一步上1阶,2阶,3阶,计算共有多少种不同的走法、NOIP2006提高组题:能量项链,求大神指出我的代码逻辑错误、最小编辑距离算法 怎么得到路径等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zz/10067041.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-04
下一篇2023-05-04

发表评论

登录后才能评论

评论列表(0条)

    保存