• Acwing------动态规划


    动态规划

    背包问题

    状态表示

    1.集合:所有只考虑前i个物品,且总体积不大于j的所有选法

    2.属性:MAX

    2.1 去掉k个物品i
    2.2 求MAX,f【i - 1】【j - k * v】
    2.3 再加回来k个物品i

    状态计算:集合的划分

    1. 0-1背包(Acwing-2)

    朴素做法

    #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 - 1][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 = m; j >= v[i]; --j) {
                f[j] = max(f[j], f[j - v[i]]+ w[i]);
            }
        }
        
        cout << f[m] << endl;
        
        return 0;
    }
    
    

    2.完全背包(Acwing-3)

    朴素做法

    #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 - v[i] * k] + w[i] * k);
                }
            }
        }
        
        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][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.多重背包-I(Acwing)

    朴素做法

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

    二进制优化

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 25000, M = 2000;
    int n, m, cnt = 0;
    int v[N], w[N];
    int f[N];
    
    int main() {
        cin >> n >> m;
        for (int i = 1; i <= n; ++i) {
            int a, b, s, k = 1;
            cin >> a >> b >> s;
            while (k <= s) {
                cnt ++;
                v[cnt] = a * k;
                w[cnt] = b * k;
                s -= k;
                k *= 2;
            }
            if (s > 0) {
                cnt++;
                v[cnt] = a * s;
                w[cnt] = b * s;
            }
        }
        
        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;
    }
    

    分组背包(Acwing-9)

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 110;
    int n, m;
    int v[N][N], w[N][N], s[N];
    int f[N];
    
    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

    • 递推方程存在线性关系

    数字三角形(Acwing-898)

    #include <iostream>
    using namespace std;
    
    const int N = 510;
    
    int n, INF = 1e9;
    int a[N][N], f[N][N];
    
    int main() {
        cin >> n;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= i; ++j) {
                f[i][j] = -INF;
                cin >> 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], f[i - 1][j]) + a[i][j];
            }
        }
        
        int res = -INF;
        for (int i = 1; i <= n; ++i) res = max(res, f[n][i]);
        cout << res << endl;
        
        return 0;
    }
    

    最长上升子序列(Acwing-895)

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

    最长上升子序列-II(Acwing-896)

    #include <iostream>
    using namespace std;
    
    const int N = 100010;
    int n, a[N], f[N];
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; ++i) cin >> a[i];
        
        int len = 0;
        f[0] = -2e9;
        for (int i = 0; i < n; ++i) {
            int l = 0, r = len;
            while (l < r) {
                int mid = l + r + 1 >> 1;
                if (f[mid] < a[i]) l = mid;
                else r = mid - 1;
            }
            len = max(len, r + 1);
            f[r + 1] = a[i];
        }
        
        cout << len << endl;
        return 0;
    }
    

    最长公共子序列(Acwing-897)

    #include <iostream>
    using namespace std;
    
    const int N = 1010;
    int n, m;
    char a[N], b[N];
    int f[N][N];
    
    int main () {
        cin >> 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);
            }
        }
        
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    最短编辑距离(Acwing-902)

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N = 1010;
    int n, m;
    char a[N], b[N];
    int f[N][N];
    
    int main() {
        scanf("%d%s", &n, a + 1);
        scanf("%d%s", &m, b + 1);
        
        for (int i = 0; i <= m; ++i) f[0][i] = i;
        for (int i = 0; i <= n; ++i) f[i][0] = i;
        
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                f[i][j] = min(f[i - 1][j], f[i][j - 1]) + 1;
                if (a[i] == b[j]) f[i][j] = min(f[i][j], f[i - 1][j - 1]);
                else f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
            }
        }
        cout << f[n][m] << endl;
        
        return 0;
    }
    

    区间DP

    石子合并(Acwing-282)

    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int N = 310;
    int n, s[N], f[N][N];
    
    int main() {
        cin >> n;
        for (int i = 1;i <= n; ++i) cin >> 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] = 1e9;
                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]);
                }
            }
        }
        cout << f[1][n] << endl;
        
        return 0;
    }
    
  • 相关阅读:
    PO BO VO DTO POJO DAO DO这些Java中的概念分别指一些什么?
    前端面试题汇总(待续)
    vue lottie vue-lottie : 使用教程
    webstorm 换行时 代码不对齐
    webstorm 导出编辑器配置.editorconfig
    vue 查看dist文件里的结构
    vue-cli 生产打包
    element form 校验数组每一项
    typescript无法识别vue中的$refs
    mac 10.14.5 [vue create的时候 mkdir没有权限]
  • 原文地址:https://www.cnblogs.com/clown9804/p/12426404.html
Copyright © 2020-2023  润新知