终于要开始了。。。。。。。。
万能的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 }
------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------
只有不断学习才能进步!
来源:https://www.cnblogs.com/wenbao/p/6653625.html