• FUNDAMENTAL PART4 DP


    DP

    +++

    一.背包问题

    1.01背包

    二维数组状态转移

    #include <iostream>
    
    using namespace std;
    
    const int N = 1010;
    
    int v[N], w[N];
    int n, m;
    int f[N][N];
    
    int main()
    {
        cin >> n >> m;
        
        for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
        
        for (int i = 1; i <= n; i ++ )
            for (int j = 0; j <= m; j ++ )
            {
                f[i][j] = f[i - 1][j];
                if(j >= v[i]) f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
            }
            
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    一维数组状态转移

    #include <iostream>
    
    using namespace std;
    
    const int N = 1010;
    
    int v[N], w[N];
    int n, m;
    int f[N];
    
    int main()
    {
        cin >> n >> m;
        
        for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
        
        for (int i = 1; i <= n; i ++ )
            for (int j = m; j >= v[i]; j -- )
                f[j] = max(f[j], f[j - v[i]] + w[i]);    
            
        cout << f[m] << endl;
        
        return 0;
    }
    
    2.完全背包问题

    未优化做法(TLE)

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int v[N], w[N];
    int f[N][N];
    
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
        
        for (int i = 1; i <= n; i ++ )
            for (int j = 0; j <= m; j ++ )
                for (int k = 0; k * v[i] <= j; k ++ )
                    f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
        
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    优化做法1.

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int v[N], w[N];
    int f[N][N];
    
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
        
        for (int i = 1; i <= n; i ++ )
            for (int j = 0; j <= m; j ++ )
            {
                f[i][j] = f[i - 1][j];
                if(j >= v[i]) f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]);
            }
        
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    状态转移方程优化为一维数组(滚动数组)

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int n, m;
    int v[N], w[N];
    int f[N];
    
    int main()
    {
        cin >> n >> m;
        for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
        
        for (int i = 1; i <= n; i ++ )
            for (int j = v[i]; j <= m; j ++ )
                f[j] = max(f[j], f[j - v[i]] + w[i]);
        
        cout << f[m] << endl;
        
        return 0;
    }
    
    3.多重背包问题的二进制优化
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 25000, M = 2010;
    
    int n, m;
    int v[N], w[N];
    int f[M];
    
    int main()
    {
        cin >> n >> m;
        
        int cnt = 0;
        for (int i = 1; i <= n; i ++ )
        {
            int a, b, s;
            scanf("%d%d%d", &a, &b, &s);
            int k = 1;
            
            while(k <= s)
            {
                cnt ++ ;
                v[cnt] = a * k;
                w[cnt] = b * k;
                s -= k;
                k *= 2;
            }
            
            if(s > 0)
            {
                cnt ++ ;
                v[cnt] = s * a;
                w[cnt] = s * b;
            }
        }
        
        n = cnt;
        
        for (int i = 1; i <= n; i ++ )
            for (int j = m; j >= v[i]; j -- )
                f[j] = max(f[j], f[j - v[i]] + w[i]);
                
        cout << f[m] << endl;
        
        return 0;
    }
    
    5.分组背包问题
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 110;
    
    int v[N][N], w[N][N];
    int f[N], s[N];
    int n, m;
    
    int main()
    {
        cin >> n >> m;
        
        for (int i = 1; i <= n; i ++ )
        {
            cin >> s[i];
            for (int j = 0; j < s[i]; j ++ )
                cin >> v[i][j] >> w[i][j];
        }
        
        for (int i = 1; i <= n; i ++ )
            for (int j = m; j >= 0; j -- )
                for (int k = 0; k < s[i]; k ++ )
                    if(v[i][k] <= j)
                        f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
        
        cout << f[m] << endl;
        
        return 0;
    }
    

    二.线性DP

    1.数字三角形
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 510, INF = 0x3f3f3f3f;
    
    int a[N][N], f[N][N];
    int n;
    
    int main()
    {
        scanf("%d", &n);
        
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= i; j ++ )
                scanf("%d", &a[i][j]);
        
        for (int i = 0; i <= n; i ++ )
            for (int j = 0; j <= i + 1; j ++ )
                f[i][j] = -INF;
        
        f[1][1] = a[1][1];
        for (int i = 2; i <= n; i ++ )
            for (int j = 1; j <= i; j ++ )
                f[i][j] = max(f[i  -1][j - 1] + a[i][j], f[i - 1][j] + a[i][j]); 
        
        int res = -INF;
        for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);
        
        printf("%d
    ", res);
        
        return 0;
    }
    
    2.最长上升子序列

    1.O(n²)做法

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    int a[N], f[N];
    int n;
    
    int main()
    {
        scanf("%d", &n);
        
        for (int i = 1; i <= n; i ++ ) scanf("%d", a + i);
        
        for (int i = 1; i <= n; i ++ )
        {
            f[i] = 1;
            for (int j = 1; j < i; j ++ )
                if(a[i] > a[j])
                    f[i] = max(f[i], f[j] + 1);
        }
        
        int res = 0;
        for (int i = 1; i <= n; i ++ ) res = max(res, f[i]);
        
        printf("%d
    ", res);
        
        return 0;
    }
    
    3.最长公共子序列
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 1010;
    
    char a[N], b[N];
    int f[N][N];
    int n, m;
    
    int main()
    {
        scanf("%d%d", &n, &m);
        scanf("%s%s", a + 1, b + 1);
        
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= m; j ++ )
            {
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
                if(a[i] == b[j]) f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
            }
            
        printf("%d
    ", f[n][m]);
        
        return 0;
    }
    
    4.石子合并(区间DP)
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 310;
    
    int s[N];
    int n;
    int f[N][N];
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ ) scanf("%d", s + i);
        
        for (int i = 1; i <= n; i ++ ) s[i] += s[i - 1];
        
        for (int len = 2; len <= n; len ++ )
            for (int i = 1; i + len - 1 <= n; i ++ )
            {
                int l = i, r = i + len - 1;
                f[l][r] = 1e8;
                
                for (int k = l; k < r; k ++ )
                    f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
            }
            
        printf("%d
    ", f[1][n]);
        
        return 0;
    }
    
  • 相关阅读:
    37.1 net-- udp传输
    37 net 网络编程
    review
    java day02 记录
    36.2 线程生命周期
    36.1 线程锁
    36 Thread 多线程
    35 编码 ASCII Unicode UTF-8 ,字符串的编码、io流的编码
    34.6 Properties(k,v存储) 和io流结合使用
    今日学习总结
  • 原文地址:https://www.cnblogs.com/scl0725/p/13876116.html
Copyright © 2020-2023  润新知