• wenbao与动态规划


    终于要开始了。。。。。。。。

    万能的dp

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    动规入门级题目 数字三角形

    不多说

    http://lx.lanqiao.cn/problem.page?gpid=T312

     1 #include <iostream>
     2 using namespace std;
     3 int a[105][105];
     4 int main(){
     5     int n;
     6     scanf("%d", &n);
     7     for(int i = 0; i < n; ++i){
     8         for(int j = 0; j <= i; ++j){
     9             scanf("%d", &a[i][j]);
    10         }
    11     }
    12     for(int i = n-2; i >= 0; --i){
    13         for(int j = 0; j <= i; ++j){
    14             a[i][j] = a[i][j] + max(a[i+1][j], a[i+1][j+1]);
    15             //cout<<i<<" "<<j<<" "<<a[i][j]<<endl;
    16         }
    17     }
    18     printf("%d
    ", a[0][0]);
    19     return 0;
    20 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    DAG动规入门级别题目矩形嵌套

    不多说

    http://acm.nyist.net/JudgeOnline/problem.php?pid=16

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <vector>
     5 #include <stdio.h>
     6 using namespace std;
     7 int n;
     8 int vis[1009];
     9 vector<int> v[1009];
    10 struct Node{
    11     int x, y;
    12 }T[1009];
    13 bool OK(int i, int j){
    14     if((T[i].x < T[j].x && T[i].y < T[j].y) || (T[i].y < T[j].x && T[i].x < T[j].y))
    15         return true;
    16     return false;
    17 }
    18 int d(int x){
    19     if(vis[x]) return vis[x];
    20     int sum = 1;
    21     for(int i = 0; i < v[x].size(); ++i){
    22         int xx = v[x][i];
    23         sum = max(sum, d(xx) + 1);
    24     }
    25     return vis[x] = sum;
    26 }
    27 int main(){
    28     int t;
    29     scanf("%d", &t);
    30     while(t--){
    31         memset(vis, 0, sizeof(vis));
    32         int ma = -1;
    33         scanf("%d", &n);
    34         for(int i = 0; i < n; ++i){
    35             v[i].clear();
    36             scanf("%d%d", &T[i].x, &T[i].y);
    37             for(int j = 0; j < i; ++j){
    38                 if(OK(i, j)){
    39                     v[i].push_back(j);
    40                 }
    41                 if(OK(j, i)){
    42                     v[j].push_back(i);
    43                 }
    44             }
    45         }
    46         for(int i = 0; i < n; ++i){
    47             int xx = d(i);
    48             if(xx > ma) ma = xx;
    49         }
    50         printf("%d
    ", ma);
    51     }
    52     return 0;
    53 }

    ---------------------------------------------------------------------------

    简单dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1051

    计算最大矩形

     1 #include "iostream"
     2 #include <stdio.h>
     3 using namespace std;
     4 
     5 #define ll long long
     6 const int maxn = 555;
     7 int n, m;
     8 ll a[maxn][maxn], r[maxn][maxn], b[maxn][maxn];
     9 
    10 int main() {
    11 #ifdef wenbao
    12     freopen("in", "r", stdin);
    13 #endif
    14     scanf("%d%d", &m, &n);
    15     for (int i = 1; i <= n; ++i) {
    16         for (int j = 1; j <= m; ++j) {
    17             scanf("%lld", &a[i][j]);
    18             r[i][j] = r[i][j-1] + a[i][j];
    19         }
    20     }
    21     ll ma = -1;
    22     for (int i = 1; i <= n; ++i) {
    23         for (int j = 1; j <= m; ++j) {
    24             for(int k = 1; k <= j; ++k){
    25                 ll x = r[i][j] - r[i][k-1];
    26                 b[k][j] = max(b[k][j]+x, x);
    27                 if(b[k][j] > ma) ma = b[k][j];
    28             }
    29         }
    30     }
    31     printf("%d
    ", ma > 0 ? ma : 0);
    32     return 0;
    33 
    34 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    DAG经典题目最少硬币问题

    http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1221

    建议认真思考

     1 #include <iostream>
     2 #include <string.h>
     3 using namespace std;
     4 int t, m;
     5 int a[11], b[11];
     6 int c[20009];
     7 int main(){
     8     scanf("%d", &t);
     9     for(int i = 0; i < t; ++i){
    10         scanf("%d%d", a+i, b+i);
    11     }
    12     scanf("%d", &m);
    13     memset(c, 0x3f, sizeof(c));
    14     c[0] = 0;
    15     for(int i = 0; i < t; ++i){
    16         for(int j = 1; j <= b[i]; ++j){
    17             for(int k = m; k >= a[i]; --k){
    18                 c[k] = min(c[k], c[k-a[i]]+1);
    19             }
    20         }
    21     }
    22     printf("%d
    ", c[m] >= m ? -1 : c[m]);
    23     return 0;
    24 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     DAG

    城市间谍https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=245&page=show_problem&problem=3466 (uva 1025)

    确定状态,可以等一分钟,也可以坐向右的车(如果有)也可以坐向左的车(如果有)

    经典题目

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 using namespace std;
     5 const int INF = 1e9;
     6 int n, t, m1, m2, x;
     7 int a[55], d[205][55];
     8 bool vis[55][205][2];
     9 int main(){
    10     int ca = 1;
    11     while(~scanf("%d", &n) && n){
    12         memset(vis, false, sizeof(vis));
    13         scanf("%d", &t);
    14         for(int i = 1; i < n; ++i){
    15             scanf("%d", a+i);
    16         }
    17         scanf("%d", &m1);
    18         for(int i = 0; i < m1; ++i){
    19             scanf("%d", &x);
    20             for(int j = 1; j < n; ++j){
    21                 if(x <= t) vis[j][x][0] = true;
    22                 x += a[j];
    23             }
    24         }
    25         scanf("%d", &m2);
    26         for(int i = 0; i < m2; ++i){
    27             scanf("%d", &x);
    28             for(int j = n-1; j >= 1; --j){
    29                 if(x <= t) vis[j+1][x][1] = true;
    30                 x += a[j];
    31             }
    32         }
    33         for(int i = 1; i < n; ++i) d[t][i] = INF;
    34         d[t][n] = 0;
    35         for(int i = t-1; i >= 0; --i){
    36             for(int j = 1; j <= n; ++j){
    37                 d[i][j] = d[i+1][j] + 1;
    38                 if(j < n && vis[j][i][0] && i+a[j] <= t){
    39                     d[i][j] = min(d[i][j], d[i+a[j]][j+1]);
    40                 }
    41                 if(j > 1 && vis[j][i][1] && i+a[j-1] <= t){
    42                     d[i][j] = min(d[i][j], d[i+a[j-1]][j-1]);
    43                 }
    44             }
    45         }
    46         if(d[0][1] >= INF) printf("Case Number %d: impossible
    ", ca++);
    47         else printf("Case Number %d: %d
    ", ca++, d[0][1]);
    48     }
    49     return 0;
    50 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     DAG

    巴比伦塔

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=6&page=show_problem&problem=378 (uva 437)

    小的放在大的上面求最大高度,与矩形嵌套类似

     1 #include <iostream>
     2 #include <vector>
     3 #include <string.h>
     4 using namespace std;
     5 struct Node{
     6     int x, y, z;
     7 }T[200];
     8 void add(int w, int x, int y, int z){
     9     T[w].x = x, T[w].y = y, T[w].z = z;
    10 }
    11 bool OK(int i, int j){
    12     if(T[i].x > T[j].x && T[i].y > T[j].y) return true;
    13     return false;
    14 }
    15 vector<int> v[200];
    16 int vis[200];
    17 int d(int x){
    18     if(vis[x]) return vis[x];
    19     int sum = T[x].z;
    20     for(int i = 0; i < v[x].size(); ++i){
    21         int xx = v[x][i];
    22         sum = max(sum, T[x].z+d(xx));
    23     }
    24     vis[x] = sum;
    25     return sum;
    26 }
    27 int n;
    28 int main(){
    29     int ca = 1, x, y, z;
    30     while(scanf("%d", &n) && n){
    31         int num = 0;
    32         for(int i = 0; i < n; ++i){
    33             scanf("%d%d%d", &x, &y, &z);
    34             add(num++, x, y, z);
    35             add(num++, y, x, z);
    36             add(num++, z, x, y);
    37             add(num++, x, z, y);
    38             add(num++, z, y, x);
    39             add(num++, y, z, x);
    40         }
    41         for(int i = 0; i < num; ++i){
    42             v[i].clear();
    43         }
    44         for(int i = 0; i < num; ++i){
    45             for(int j = 0; j < num; ++j){
    46                 if(OK(i, j)) v[i].push_back(j);
    47             }
    48         }
    49         int ma = -1;
    50         memset(vis, 0, sizeof(vis));
    51         for(int i = 0; i < num; ++i){
    52             int x = d(i);
    53             if(x > ma) ma = x;
    54         }
    55         printf("Case %d: maximum height = %d
    ", ca++, ma);
    56     }
    57     return 0;
    58 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     DAG

    旅行(经典题目)https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=446&page=show_problem&problem=4093(uva 1347)

    推荐认真思考

    从最左边的电到最右边的点再回到最左边的点,要求总的路程最短

     1 #include <iostream>
     2 #include <cmath>
     3 #include <string.h>
     4 #include <stdio.h>
     5 using namespace std;
     6 const int maxn = 1009;
     7 int n;
     8 double vis[maxn][maxn];
     9 struct Node{
    10     double x, y;
    11 }T[maxn];
    12 double dis(int i, int j){
    13     return sqrt(pow((T[i].x - T[j].x),2.0) + pow(T[i].y - T[j].y, 2.0));
    14 }
    15 double d(int i, int j){
    16     double& sum = vis[i][j];
    17     if(sum) return sum;
    18     if(i == n-1){
    19         return sum = dis(n-1, n) + dis(j, n);
    20     }
    21     sum = min(d(i+1, j)+dis(i, i+1), d(i+1, i)+dis(j, i+1));
    22     return sum;
    23 }
    24 int main(){
    25     while(~scanf("%d", &n)){
    26         memset(vis, 0, sizeof(vis));
    27         for(int i = 1; i <= n; ++i){
    28             scanf("%lf%lf", &T[i].x, &T[i].y);
    29         }
    30         double x = d(2, 1) + dis(1, 2);
    31         printf("%.2lf
    ", x);
    32     }
    33     return 0;
    34 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     多阶段决策

    单向TSp  https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&page=show_problem&problem=52(uva 116)

    从左边第一列到右边第一列,规定每次可以向右,右上,右下移动,要求和最小

     1 #include <iostream>
     2 #include <algorithm>
     3 using namespace std;
     4 const int INF = 1e9;
     5 int n, m;
     6 int d[11][101], a[11][101], c[11][101];
     7 int main(){
     8     while(~scanf("%d%d", &m, &n)){
     9         for(int i = 1; i <= m; ++i){
    10             for(int j = 1; j <= n; ++j){
    11                 scanf("%d", &a[i][j]);
    12             }
    13         }
    14         int num = INF, id;
    15         for(int i = n; i >= 1; --i){
    16             for(int j = 1; j <= m; ++j){
    17                 if(i == n){
    18                     d[j][i] = a[j][i];
    19                 }else{
    20                     int b[3] = {j-1, j, j+1};
    21                     if(j == 1) b[0] = m;
    22                     if(j == m) b[2] = 1;
    23                     sort(b, b+3);
    24                     int sum = INF;
    25                     for(int k = 0; k < 3; ++k){
    26                         if(d[b[k]][i+1]+a[j][i] < sum){
    27                             sum = d[b[k]][i+1]+a[j][i], c[j][i] = b[k];
    28                         }
    29                     }
    30                     d[j][i] = sum;
    31                 }
    32                 if(i == 1 && d[j][i] < num){
    33                     num = d[j][i], id = j;
    34                 }
    35             }
    36         }
    37         printf("%d", id);
    38         for(int i = 1; i < n; id = c[id][i], ++i){
    39             printf(" %d", c[id][i]);
    40         }
    41         printf("
    %d
    ", num);
    42     }
    43     return 0;
    44 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     多阶段决策

    ktv唱歌

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=441&page=show_problem&problem=4008 (uva 12563)

    输入时间t,n首歌,要求唱的歌尽量多的前提下时间尽量长

    01背包

     1 #include <iostream>
     2 #include <string.h>
     3 using namespace std;
     4 const int maxn = 1e5+10;
     5 int d[maxn];
     6 int main(){
     7     int t;
     8     scanf("%d", &t);
     9     for(int y = 1; y <= t; ++y){
    10         int n, m, x, ma;
    11         scanf("%d%d", &n, &m);
    12         memset(d, 0x8f, sizeof(d));
    13         d[0] = 0;
    14         for(int i = 0; i < n; ++i){
    15             scanf("%d", &x);
    16             for(int j = m-1; j >= x; --j){
    17                 d[j] = max(d[j], d[j-x]+1);
    18             }
    19         }
    20         for(int i = ma = m-1; i >= 0; --i){
    21             if(d[i] > d[ma]) ma = i; 
    22         }
    23         printf("Case %d: %d %d
    ", y, d[ma]+1, ma+678);
    24     }
    25     return 0;
    26 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    线性结构上的动规

    照明系统设计 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=26&page=show_problem&problem=2395(uva 11400)

    给定n个灯泡,每个灯泡的电压,电源费用,灯泡费用,灯泡数量,要求将低电压换位高电压的最优方案(不同种类灯泡不同电源,相同灯泡可以同种电源)

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <string.h>
     4 using namespace std;
     5 struct Node{
     6     int v, k, c, l;
     7 }T[1005];
     8 bool cmp(Node a, Node b){
     9     return a.v < b.v;
    10 }
    11 int s[1005], d[1005];
    12 int main(){
    13     int t;
    14     while(~scanf("%d", &t) && t){
    15         for(int i = 1; i <= t; ++i){
    16             scanf("%d%d%d%d", &T[i].v, &T[i].k, &T[i].c, &T[i].l);
    17         }
    18         sort(T+1, T+t+1, cmp);
    19         memset(d, 0x3f, sizeof(d));
    20         s[0] = d[0] = 0;
    21         for(int i = 1; i <= t; ++i){
    22             s[i] = (i == 1 ? T[i].l : s[i-1]+T[i].l);
    23             for(int j = i-1; j >= 0; j--){
    24                 d[i] = min(d[i], (s[i]-s[j])*T[i].c+T[i].k+d[j]);
    25             }
    26         }
    27         printf("%d
    ", d[t]);
    28     }
    29     return 0;
    30 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    线性动规 

    划分最少回文串

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=27&page=show_problem&problem=2631(uva 11584)

     1 #include <iostream>
     2 #include <string.h>
     3 using namespace std;
     4 const int maxn = 1009;
     5 char str[maxn];
     6 int d[maxn];
     7 bool ok(int i, int j){
     8     while(i < j){
     9         if(str[i] != str[j]) return false;
    10         i ++, j --;
    11     }
    12     return true;
    13 }
    14 int main(){
    15     int t;
    16     scanf("%d", &t);
    17     while(t--){
    18         scanf("%s", str+1);
    19         int len = strlen(str+1);
    20         d[0] = 0;
    21         for(int i = 1; i <= len; ++i){
    22             d[i] = i;
    23             for(int j = 1; j <= i; ++j){
    24                 if(ok(j, i)){
    25                     d[i] = min(d[i], d[j-1]+1);
    26                 }
    27             }
    28         }
    29         printf("%d
    ", d[len]);
    30     }
    31     return 0;
    32 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     http://qscoj.cn/problem/74/

    中文题。。。。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <string>
     4 #include <map>
     5 #include <string.h>
     6 using namespace std;
     7 #define ll long long
     8 ll a[2009];
     9 ll vis[2009][2009];
    10 int n;
    11 ll d(int x, int y, int num){
    12     if(vis[x][y]) return vis[x][y];
    13     return vis[x][y] = (x == y ? n*a[x] : max(num*a[y]+d(x, y-1, num+1), num*a[x]+d(x+1, y, num+1)));
    14 }
    15 int main(){
    16     while(~scanf("%d", &n)){
    17         memset(vis, 0, sizeof(vis));
    18         for(int i = 0; i < n; ++i){
    19             scanf("%d", &a[i]);
    20         }
    21         printf("%lld
    ", d(0, n-1, 1));
    22     }
    23     return 0;
    24 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

     http://acm.hdu.edu.cn/showproblem.php?pid=5903

    给定n(even)长度的字符串,求与给定串恰有m个不同字符的循环串(前一半与后一半相同),要求字典序最小

    dp预处理+贪心

    a[i][j] 表示第i位可以改变j个字符

     1 #include <iostream>
     2 #include <string.h>
     3 using namespace std;
     4 const int maxn = 1005;
     5 char str[maxn];
     6 bool a[maxn][maxn];
     7 int main(){
     8     int t, n, m;
     9     scanf("%d", &t);
    10     while(t--){
    11         memset(a, false, sizeof(bool)*maxn*maxn);
    12         scanf("%d%d%s", &n, &m, str);
    13         int xx = n/2;
    14         a[xx][0] = true;
    15         for(int i = xx-1; i >= 0; --i){
    16             if(str[i] == str[i+xx]){
    17                 for(int j = 0; j <= m; ++j) a[i][j] = a[i+1][j];
    18                 for(int j = 0; j <= m-2; ++j) if(a[i+1][j]) a[i][j+2] = true;
    19             }else{
    20                 for(int j = 0; j <= m-1; ++j) if(a[i+1][j]) a[i][j+1] = true;
    21                 for(int j = 0; j <= m-2; ++j) if(a[i+1][j]) a[i][j+2] = true;
    22             }
    23         }
    24         if(!a[0][m]){
    25             printf("Impossible
    ");
    26             continue;
    27         }else{
    28             for(int i = 0; i < xx; ++i){
    29                 for(int j = 0; j < 26; ++j){
    30                     int x = 0;
    31                     if(str[i] != 'a'+j) ++x;
    32                     if(str[i+xx] != 'a'+j) ++x;
    33                     if(a[i+1][m-x]){
    34                         str[i] = str[i+xx] = 'a'+j;
    35                         m -= x;
    36                         break;
    37                     }
    38                 }
    39             }
    40         }
    41         printf("%s
    ", str);
    42     }
    43     return 0;
    44 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    字符串dp

    http://acm.hdu.edu.cn/showproblem.php?pid=6170

    字符串匹配

    同时可以利用正则(强)

     1 #include <iostream>
     2 #include <string.h>
     3 using namespace std;
     4 const int maxn = 2509;
     5 bool vis[maxn][maxn];
     6 char str[maxn], ss[maxn];
     7 int main(){
     8     int t;
     9     scanf("%d", &t);
    10     while(t--){
    11         scanf("%s%s", str+1, ss+1);
    12         int len1 = strlen(str+1), len2 = strlen(ss+1);
    13         memset(vis, false, sizeof(vis));
    14         vis[0][0] = true;
    15         for(int i = 1; i <= len2; ++i){
    16             if(i >= 2 && ss[i] == '*'){
    17                 vis[i][0] |= vis[i-2][0];
    18             }
    19             for(int j = 1; j <= len1; ++j){
    20                 if(ss[i] == '.' || ss[i] == str[j]){
    21                     vis[i][j] = vis[i-1][j-1];
    22                 }else if(ss[i] == '*'){
    23                     vis[i][j] = vis[i-1][j] | vis[i-2][j];
    24                     if(str[j-1] == str[j] &&(vis[i-1][j-1] || vis[i][j-1]))
    25                         vis[i][j] = true;
    26                 }
    27             }
    28         }
    29         printf("%s
    ", vis[len2][len1] ? "yes" : "no");
    30     }
    31     return 0;
    32 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    --------------------------------

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------

    只有不断学习才能进步!

  • 相关阅读:
    深入PHP内核之全局变量
    关于PHP中的opcode
    深入PHP内核之opcode handler
    virtual memory exhausted: Cannot allocate memory
    Nginx配置error_page 404错误页面
    PHP 与 UTF-8
    define() vs const 该如何选择?
    CentOS安装配置Samba
    当···时发生了什么?
    PHP中curl的使用
  • 原文地址:https://www.cnblogs.com/wenbao/p/6653625.html
Copyright © 2020-2023  润新知