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\n", 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\n", 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\n", 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\n", 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\n", ca++);
47         else printf("Case Number %d: %d\n", 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\n", 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\n", 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("\n%d\n", 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\n", 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\n", 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\n", 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\n", 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\n");
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\n", 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\n", vis[len2][len1] ? "yes" : "no");
30     }
31     return 0;
32 }

 

 

 

 

 

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

 

 

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

 

 

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

 

 

 

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

 

 

 

 

 

只有不断学习才能进步!

 

posted @ 2018-04-14 13:48  wenbao  阅读(136)  评论(0编辑  收藏  举报