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 }
------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------
只有不断学习才能进步!