算法复习(四五六)

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法复习(四五六)相关的知识,希望对你有一定的参考价值。

动态规划

动态规划算法的有效性依赖于问题本身所具有的两个重要性质:最优子结构、重叠子问题

关于动态规划算法和备忘录方法的适用条件:

要求:
用分治法和动态规划法分别解决最大子段和问题(第四步求最优解不需要掌握)

掌握用动态规划法解决0-1背包问题

最长单调递增子序列

最长公共子序列(会写出计算最长公共子序列长度的递推式即可)

矩阵连乘问题

备忘录做法:

signed main()

    cin>>n;
    for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dp[i][j]=inf;
    for(int i=1;i<=n;i++) dp[i][i]=0;
    for(int i=1;i<=n;i++)
        cin>>row[i]>>col[i];
    for(int i=1;i<=n;i++) p[i]=col[i];
    p[0]=row[1];
    for(int len=2;len<=n;len++)
    
        for(int i=1;i<=n-len+1;i++)
        
            int j=i+len-1;
            dp[i][j]=dp[i+1][j]+p[i-1]*p[i]*p[j];
            s[i][j]=i;
            for(int k=i+1;k<j;k++)
            
                int tmp=dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
                if(tmp<dp[i][j])
                
                    dp[i][j]=tmp;
                    s[i][j]=k;
                
            
        
    
    cout<<dp[1][n]<<endl;
    dfs(1,n);
    return 0;

动态规划做法:

signed main()

    cin>>n;
    for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dp[i][j]=inf;
    for(int i=1;i<=n;i++) dp[i][i]=0;
    for(int i=1;i<=n;i++)
        cin>>row[i]>>col[i];
    for(int i=1;i<=n;i++) p[i]=col[i];
    p[0]=row[1];
    for(int len=2;len<=n;len++)
    
        for(int i=1;i<=n-len+1;i++)
        
            int j=i+len-1;
            dp[i][j]=dp[i][i]+dp[i+1][j]+p[i-1]*p[i]*p[j];
            s[i][j]=i;
            for(int k=i+1;k<j;k++)
            
                if(dp[i][j]>dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j])
                
                    dp[i][j]=dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
                    s[i][j]=k;
                
            
        
    
    cout<<dp[1][n]<<endl;
    print(1,n);
    return 0;

最大子段和问题

法一:

#include <bits/stdc++.h>
#define endl '\\n'
#define int long long
using namespace std;
const int N=1e3+5;
const int inf=1e18;
int n,a[N],dp[N];

signed main()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans=0;
    for(int i=1;i<=n;i++)
    
        dp[i]=max(dp[i-1]+a[i],0ll);
        ans=max(ans,dp[i]);
    
    cout<<ans<<endl;
    return 0;

/*
7
-2 11 -4 13 -5 -2 -100
*/

法二:

signed main()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    int ans=0,b=0;
    for(int i=1;i<=n;i++)
    
        if(b>0)
            b+=a[i];
        else
            b=a[i];
        ans=max(ans,b);
    
    cout<<ans<<endl;
    return 0;

法三:

#include <bits/stdc++.h>
#define endl '\\n'
#define int long long
using namespace std;
const int N=1e3+5;
const int inf=1e18;
int n,a[N],dp[N];
int dfs(int l,int r)

    if(l==r)
        return a[l]>0?a[l]:0;
    int sum=0,mid=(l+r)/2;
    int left=dfs(l,mid);
    int right=dfs(mid+1,r);
    int s1=0,s2=0,tmp=0;
    for(int i=mid;i>=l;i--)
    
        tmp+=a[i];
        if(s1<tmp) s1=tmp;
    
    tmp=0;
    for(int i=mid+1;i<=r;i++)
    
        tmp+=a[i];
        if(s2<tmp) s2=tmp;
    
    sum=s1+s2;
    if(left>sum) sum=left;
    if(right>sum) sum=right;
    return sum;

signed main()

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cout<<dfs(1,n)<<endl;
    return 0;

/*
7
-2 11 -4 13 -5 -2 100
*/

01背包问题

int n,m,f[105][N],dp[N];

void fun1()

    for(int i=1;i<=n;i++)   //物品i
    
        for(int j=1;j<=m;j++)   //容量j
        
            if(j<w[i])
                f[i][j]=f[i-1][j];
            else 
                f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
        
    
    cout<<f[n][m]<<endl;

void fun2() //逆序更新

    for(int i=1;i<=n;i++)
    
        for(int j=m;j>=w[i];j--)
            dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
    


最长单调递增子序列

for(int i=1;i<=n;i++) cin>>a[i],dp[i]=1;
    for(int i=2;i<=n;i++)
    
        for(int j=1;j<i;j++)
        
            if(a[j]<=a[i])
                dp[i]=max(dp[i],dp[j]+1);
        
    
    cout<<dp[n]<<endl;

最长公共子序列


    cin>>s1>>s2;
    len1=s1.length(),len2=s2.length();
    s1=" "+s1,s2=" "+s2;
    for(int i=1;i<=len1;i++)
    
        for(int j=1;j<=len2;j++)
        
            if(s1[i]==s2[j]) dp[i][j]=dp[i-1][j-1]+1,s[i][j]=1;
            else
            
                if(dp[i-1][j]>dp[i][j-1])
                
                    dp[i][j]=dp[i-1][j];s[i][j]=2;//上面
                
                else
                    dp[i][j]=dp[i][j-1];s[i][j]=3;
            
        
    
    cout<<dp[len1][len2]<<endl;
    return 0;

贪心算法

适合于贪心算法求解的问题具有:贪心选择性质、最优子结构性质
贪心算法可以获取到问题的局部最优解,不一定能获取到全局最优解
掌握使用贪心算法解决:活动安排问题、背包问题、最优装载问题(件数最多)、删数问题

活动安排问题

按照结束时间进行排序

int n,p[N];
struct node

    int st,ed,id;
a[N];
bool cmp(node a,node b)

    return a.ed<b.ed;

signed main()

    cin>>n;
    for(int i=1;i<=n;i++) 
    
        cin>>a[i].st>>a[i].ed;
        a[i].id=i;
    
    sort(a+1,a+n+1,cmp);
    p[1]=1;
    int ans=1,tmp=a[1].ed;
    for(int i=2;i<=n;i++)
    
        if(a[i].st>=tmp)
        
            tmp=a[i].ed;ans++;
            p[i]=1;
        
    
    cout<<ans<<endl;
    return 0;

背包问题

int n,p[N];
struct node

    int w,v;
    double d;
a[N];
bool cmp(node a,node b)

    return a.d>b.d;

signed main()

    cin>>n>>c;
    for(int i=1;i<=n;i++)
    
        cin>>a[i].w>>a[i].v;
        a[i].d=a[i].v/a[i].w;
    
    sort(a+1,a+n+1,cmp);
    int i=1;
    double ans=0;
    while(i<=n&&a[i].w<=c)
    
        c-=a[i].w;ans+=a[i].v;
        i++;
    
    if(i<=n) ans+=c*a[i].d;
    cout<<ans<<endl;
    return 0;

最优装载问题(件数最多)

重量轻的先装,找找重量从小到大进行排序

删数问题

找到最近下降点

#include <bits/stdc++.h>
#define int long long

using namespace std;
const 深度优先搜索算法解释下?

一起玩转图论算法之二:图的深度优先遍历

基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

图论:图的四种最短路径算法

图论:图的四种最短路径算法

BAT手撕算法题·深度优先遍历