在线编程(三)

1.斐波那契数列
思路1:直接递归调用,时间复杂度 O(2N)

int Fibonacci(int n)
{
if(n==1 || n==2)
return n;
return Fibonacci(n-1) + Fibonacci(n-2);

}

思路2:动态规划,将前n次的结果保存,时间复杂度 O(N)

int Fibonacci(int n)
{
if(n==1 || n==2)
return n;
int now=1;
int pre=1;
for(int i=2;i<n;i++)
{
now=now+pre;    
pre=now-pre;
}
return now;
}

思路3: F(n)=F(n1)+F(n2
可以写成矩阵的形式:
(F(n),F(n1))=(F(n1),F(n2))[1110]

由上式可以得到:

(F(n),F(n1))=(F(2),F(1))[1110]n2

//注:懒得换编译器,还是用的vs2008,一些C++11的特性不支持,矩阵赋值比较繁琐,可以考虑重写个矩阵的类,重载=
vector<vector<int>>  multMatrix(vector<vector<int>> a,vector<vector<int>> b)//矩阵乘法
{
    int temp=0;
    vector<int> tmp;
    vector<vector<int>> res;
    for(int i=0;i<a.size();i++)//m
    {
        for(int j=0;j<b[0].size();j++)//n
        {
            for(int k=0;k<a[0].size();k++)//n
            {
                temp+=a[i][k]*b[k][j];              
            }
            tmp.push_back(temp);
            temp=0;
        }
        res.push_back(tmp);
        tmp.clear();
    }
    return res;
}

vector<vector<int>> powerN(vector<vector<int>> a,int n)//矩阵的n次方,这里直接写了2*2的单位阵
{
    vector<vector<int>> tmp;
    vector<vector<int>> sum;
    vector<int> temp;

    temp.push_back(a[0][0]);
    temp.push_back(a[0][1]);
    tmp.push_back(temp);
    temp.clear();
    temp.push_back(a[1][0]);
    temp.push_back(a[1][1]);
    tmp.push_back(temp);
    temp.clear();

    temp.push_back(1);
    temp.push_back(0);
    sum.push_back(temp);
    temp.clear();
    temp.push_back(0);
    temp.push_back(1);
    sum.push_back(temp);

    int m=1;
    while(n!=0)
    {
        if((n&1)!=0)
        {
            sum=multMatrix(sum,tmp);
        }
        tmp=multMatrix(tmp,tmp);
        n=n>>1; 
    }
    return sum;
}

int Fibonacci(int n)
{
    if(n==1 || n==2)
        return 1;
    vector<vector<int>> a;
    vector<vector<int>> b;

    vector<int> temp;
    temp.push_back(1);
    temp.push_back(1);
    a.push_back(temp);
    temp.clear();
    temp.push_back(1);
    temp.push_back(0);
    a.push_back(temp);

    b= powerN(a,n-2);

    return b[0][0]+b[1][0]; 

}

类似的问题还有:台阶问题(初始值不同),牛的繁殖问题 F(n)=F(n1)+F(n3

2.矩阵的最小路径和:给定一个矩阵,从矩阵的左上角开始,每次向下或向右,最后到达右下角的位置,路径上的所有数字加起来就是路径和。
思路:dp[i][j]存储从左上角到达m[i][j]的最小路径,第一行和第一列的数即为该列/该列到该位置的和。从m[0][0]到m[i][j]的路径必经过m[i][j-1]或m[i-1][j],d[i][j]=min{d[i-1][j],d[i][j-1]}+m[i][j]

int minPath(vector<vector<int>> m)
{
    vector<vector<int>> dp;
    dp.resize(m.size());
    for(int i=0;i<m.size();i++)
        dp[i].resize(m[0].size());
    dp[0][0]=m[0][0];

    for(int j=1;j<m[0].size();j++)
        dp[0][j]=dp[0][j-1]+m[0][j];


    for(int i=1;i<m.size();i++)
        dp[i][0]=dp[i-1][0]+m[i][0];

    for(int i=1;i<m.size();i++)
        for(int j=1;j<m.size();j++)
        {
            dp[i][j]=min(dp[i-1][j],dp[i][j-1])+m[i][j];
        }

    return dp[m.size()-1][m[0].size()-1];

}

思路2:减少空间复杂度的一种算法,如果列数大于行数,则从左往右更新数组,如果行数大于列数,则从上往下更新

int minPath2(vector<vector<int>> m)
{
    vector<int> dp;
    int more=max(m.size(),m[0].size());
    int less=min(m.size(),m[0].size());
    bool rowmore=more==m.size();//如果rowmore==1 说明行数大于列数
    dp.resize(less);
    dp[0]=m[0][0];
    for(int i=1;i<less;i++)
        dp[i]=dp[i-1]+(rowmore?m[0][i]:m[i][0]);
    for(int i=1;i<more;i++)
    {
        dp[0]=dp[0]+(rowmore?m[i][0]:m[0][i]);
        for(int j=1;j<less;j++)
            dp[j]=min(dp[j],dp[j-1])+(rowmore?m[i][j]:m[j][i]);
    }
    return dp[less-1];

}

3.换钱的最少货币:定义一个数组,表示货币的面值,每种货币不限数目,再给定一个值aim表示要换的钱,给出一个表示aim的最少货币数。

变:换钱的方法数

#include <iostream>
#include <vector>
using namespace std;



/**************************暴力递归**************/
 int process1(vector<int> arr,int index,int aim)
 {
     int res=0;
     if (index==arr.size())
         res=aim==0?1:0;
     else
     {
         for(int i=0;arr[index]*i<=aim;i++)
         res+=process1(arr,index+1,aim-arr[index]*i);
     }
     return res;
 }

int coins1(vector<int> arr,int aim)
{
    if(arr.size()==0 || aim==0)
        return 0;
    return  process1(arr,0,aim);
}

/*********************************************************/
 /****************************记忆搜索*********************/
 //时间复杂度O(N*aim^2)
 int process2(vector<int> arr,int index,int aim,vector<vector<int>> &map)
 {

     int res=0;
     int mapvalue;
     if (index==arr.size())
         res=aim==0?1:0;
     else
     {
         for(int i=0;arr[index]*i<=aim;i++)
         {
             mapvalue=map[index+1][aim-arr[index]*i];
             if(mapvalue!=0)
             {
                 res+=mapvalue==-1?0:mapvalue;
             }
             else
             {
                 res+=process2(arr,index+1,aim-arr[index]*i,map);
             }
         }

     }
     map[index][aim]=res==0?-1:res;
     return res;
 }

 int coins2(vector<int> arr,int aim)
 {
    vector<vector <int> > map(arr.size()+1 ,vector<int>(aim+1));

    if(arr.size()==0 || aim==0)
        return 0;
    return  process2(arr,0,aim,map);

 }


/*********************************************************/
 /****************************动态规划*********************/
 //时间复杂度O(N*aim^2)
 int coins3(vector<int> arr,int aim)
 {
     int n=arr.size();
     vector<vector<int>> dp(n,vector<int>(aim+1));
     for(int i=0;i<n;i++)
     {
         dp[i][0]=1;
     }
     for(int j=0;j<=aim;j++)
     {
         if(j%arr[0]==0)
         {
             dp[0][j]=1;
         }
         else
         {
             dp[0][j]=INT_MAX;
         }

     }
     int res=0;

     for(int i=1;i<n;i++)
         for(int j=1;j<=aim;j++)
         {
             for(int k=0;j-arr[i]*k >=0;k++)
             {
                 if(dp[i-1][j-arr[i]*k]!=INT_MAX)
                    res+=dp[i-1][j-arr[i]*k];
             }
             dp[i][j]=res;
             res=0;
         }
         return dp[n-1][aim];

 }


/*********************************************************/
 /****************************动态规划2*********************/
//时间复杂度O(N*aim)
 int coins4(vector<int> arr,int aim)
 {
     int n=arr.size();
     vector<vector<int>> dp(n,vector<int>(aim+1));
     for(int i=0;i<n;i++)
     {
         dp[i][0]=1;
     }
     for(int j=0;j<=aim;j++)
     {
         if(j%arr[0]==0)
         {
             dp[0][j]=1;
         }
         else
         {
             dp[0][j]=INT_MAX;
         }

     }
     int res=0;

     for(int i=1;i<n;i++)
         for(int j=1;j<=aim;j++)
         {
             res=dp[i-1][j];
             if(j-arr[i]>=0 && dp[i][j-arr[i]]!=INT_MAX)
                 if(res!=INT_MAX)
                   res+=dp[i][j-arr[i]];
                 else
                    res=dp[i][j-arr[i]];
             dp[i][j]=res;
             res=0;
         }
         return dp[n-1][aim];

 }

int main(){

    vector<int> arr;
    arr.push_back(5);
    arr.push_back(10);
    arr.push_back(25);
    arr.push_back(1);
    int aim=15;
//  int res1=coins1(arr,aim);
//   cout<<res1<<endl;

//  int res2=coins2(arr,aim);
//  cout<<res2<<endl;

//  int res3=coins3(arr,aim);
//  cout<<res3<<endl;

    int res4=coins4(arr,aim);
    cout<<res4<<endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值