zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    NOIP2011 D1T1 铺地毯
    NOIP2013 D1T3 货车运输 倍增LCA OR 并查集按秩合并
    POJ 2513 trie树+并查集判断无向图的欧拉路
    599. Minimum Index Sum of Two Lists
    594. Longest Harmonious Subsequence
    575. Distribute Candies
    554. Brick Wall
    535. Encode and Decode TinyURL(rand and srand)
    525. Contiguous Array
    500. Keyboard Row
  • 原文地址:https://www.cnblogs.com/clown9804/p/12426404.html
Copyright © 2011-2022 走看看