小白书部分动规习题
2015-10-23 22:33
225 查看
小白书动规书后习题: UVA 116 简单记忆化dp,一个点可以更新三个点 #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 100 + 5; #define LL long long #define inf (1000000007) LL dp[MAXN][MAXN]; int data[MAXN][MAXN]; int path[MAXN][MAXN]; int out[MAXN]; int main() { // freopen("UVA 116.in", "r", stdin); int n, m; while(scanf("%d%d", &n, &m) != EOF && n + m){ for(int i = 1 ; i <= n ; i++) for(int j = 1 ; j <= m ; j++) scanf("%d", &data[i][j]); memset(dp, 0, sizeof(dp)); for(int j = m ; j >= 1 ; j--){ for(int i = 1 ; i <= n ; i++){ if(j == m) dp[i][j] = data[i][j], path[i][j] = -2; else{ dp[i][j] = inf; if(i == n && dp[i][j] > dp[1][j + 1]) dp[i][j] = dp[1][j + 1], path[i][j] = 1 - n; if(i > 1 && dp[i][j] > dp[i - 1][j + 1]) dp[i][j] = dp[i - 1][j + 1], path[i][j] = -1; if(dp[i][j] > dp[i][j + 1]) dp[i][j] = dp[i][j + 1], path[i][j] = 0; if(i < n && dp[i][j] > dp[i + 1][j + 1]) dp[i][j] = dp[i + 1][j + 1], path[i][j] = 1; if(i == 1 && dp[i][j] > dp [j + 1]) dp[i][j] = dp [j + 1], path[i][j] = n - 1; dp[i][j] += data[i][j]; } } } // printf("dp\n"); // for(int i = 1 ; i <= n ; i++){ // for(int j = 1 ; j <= m ; j++) // printf("%lld ", dp[i][j]); // printf("\n"); // } // printf("dp\n"); // printf("path\n"); // for(int i = 1 ; i <= n ; i++){ // for(int j = 1 ; j <= m ; j++) // printf("%d ", path[i][j]); // printf("\n"); // } // printf("path\n"); LL ans = dp[1][1]; int mark = 1; for(int i = 2 ; i <= n ; i++){ if(ans > dp[i][1]) ans = dp[i][1], mark = i; } int cnt = 1; while(cnt <= m){ // printf("cnt = %d, mark = %d\n", cnt, mark); out[cnt] = mark; mark = mark + path[mark][cnt++]; } for(int i = 1 ; i < cnt ; i++){ printf("%d", out[i]); if(i == cnt - 1) printf("\n"); else printf(" "); } printf("%lld\n", ans); } return 0; } UVA 10066 裸的最长公共子序列 #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> #include <queue> using namespace std; const int MAXN = 100 + 5; int s1[MAXN], s2[MAXN]; int dp[MAXN][MAXN]; int main() { int n, m; int cas = 0; while(scanf("%d%d", &n, &m) != EOF && n + m){ for(int i = 1 ; i <= n ; i++) scanf("%d", &s1[i]); for(int i = 1 ; i <= m ; i++) scanf("%d", &s2[i]); memset(dp, 0, sizeof(dp)); for(int i = 1 ; i <= n ; i++){ for(int j = 1 ; j <= m ; j++){ if(s1[i] == s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } printf("Twin Towers #%d\nNumber of Tiles : %d\n\n", ++cas, dp [m]); } return 0; } UVA 10131 最长上升子序列,放在结构里面按照价值先排个序,然后找最长的上升子序列就行。 #include <cstdio> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 1000 + 5; struct D { int u,v; int mark; }d[MAXN]; bool cmp(D a, D b){return a.u < b.u;} int dp[MAXN], path[MAXN]; int out[MAXN]; int main() { int u, v, cnt = 0; while(scanf("%d%d", &u, &v) != EOF) d[cnt].mark = cnt + 1, d[cnt].u = u, d[cnt++].v = v; sort(d, d + cnt, cmp); for(int i = 0 ; i < cnt ; i++) dp[i] = 1, path[i] = i; for(int i = 0 ; i < cnt ; i++){ for(int j = i + 1 ; j < cnt ; j++){ if(d[i].u < d[j].u && d[i].v > d[j].v){ if(dp[j] < dp[i] + 1) dp[j] = dp[i] + 1, path[j] = i; } } } int ans = dp[0]; int mark = 0; for(int i = 1 ; i < cnt ; i++) if(ans < dp[i]) ans = dp[i], mark = i; cnt = 0; while(mark != path[mark]) out[cnt++] = mark, mark = path[mark]; out[cnt++] = mark; printf("%d\n", ans); for(int i = cnt - 1 ; i >= 0 ; i--){ printf("%d", d[out[i]].mark); // if(i) printf(" "); printf("\n"); } return 0; } UVA 10192 裸的最长公共子序列。然而不明白加了答案是1时为什么不能特判输出语句为city。 #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cstdlib> #include <string> using namespace std; const int MAXN = 100 + 5; char s1[MAXN], s2[MAXN]; int dp[MAXN][MAXN]; int main() { int cas = 0; while(1){ cin.getline(s1, MAXN); if(s1[0] == '#') break; cin.getline(s2, MAXN); int l1 = strlen(s1), l2 = strlen(s2); memset(dp, 0, sizeof(dp)); for(int i = 1 ; i <= l1 ; i++){ for(int j = 1 ; j <= l2 ; j++){ if(s1[i - 1] == s2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } // if(dp[l1][l2] != 1) printf("Case #%d: you can visit at most %d cities.\n", ++cas, dp[l1][l2]); // else // printf("Case #%d: you can visit at most %d city.\n", ++cas, dp[l1][l2]); } return 0; } UVA 147 裸的整数分化,只不过分化的种类略多。 有整数筛和记忆化+递归的写法,后者比较好写。 #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cmath> using namespace std; #define LL long long const int MAXN = 6000 + 5; int data[11] = {1, 2, 4, 10, 20, 40, 100, 200, 400, 1000, 2000}; LL dp[MAXN][11]; char str[10]; LL solve(LL num, int mark) { if(dp[num][mark] != -1) return dp[num][mark]; dp[num][mark] = 0; for(int i = 0 ; i <= mark ; i++){ if(num >= data[i]){ dp[num][mark] += solve(num - data[i], i); // if(num == 4) printf("i = %d, dp = %lld\n", i, solve(num - data[i], i)); } else break; } return dp[num][mark]; } int main() { memset(dp, -1, sizeof(dp)); for(int i = 0 ; i < 11 ; i++){ dp[0][i] = 1; } while(scanf("%s", str) != EOF){ int temp = 0; int f = 1, cnt = 0; for(int i = 0 ; i < strlen(str) ; i++){ if(str[i] == '.') {f = 0;continue;} if(f == 0) cnt++; temp = temp * 10 + str[i] - '0'; } while(cnt < 2) cnt++, temp *= 10; temp /= 5; if(temp == 0) break; // printf("temp = %d\n", temp); LL ans = solve(temp, 10); printf("%6s%17lld\n", str, ans); } return 0; } UVA 357 一样的题…… #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define LL long long const int MAXN = 30000 + 5; LL dp[MAXN][5]; int d[5] = {1, 5, 10, 25, 50}; LL solve(int num, int mark) { if(dp[num][mark] != -1) return dp[num][mark]; dp[num][mark] = 0; for(int i = 0 ; i <= mark ; i++){ if(num >= d[i]) dp[num][mark] += solve(num - d[i], i); else break; } return dp[num][mark]; } int main() { memset(dp, -1, sizeof(dp)); for(int i = 0 ; i < 5 ; i++) dp[0][i] = 1; int n; while(scanf("%d", &n) != EOF){ if(n == 0){ printf("There is only 1 way to produce 0 cents change.\n"); continue; } LL ans = solve(n, 4); if(ans == 1) printf("There is only 1 way to produce %d cents change.\n", n); else printf("There are %lld ways to produce %d cents change.\n", ans, n); } return 0; } UVA 10003 这道题不会写,所以写一下题解。 设dp[i][j]是以i到j为木棍切割点时最少消耗。然后就枚举一下是先切割了中间的哪一个点,然后递归处理dp[i][k]和dp[k][j]即可。其实就是简单的区间DP。 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <iostream> #include <cstdlib> using namespace std; const int MAXN = 50 + 5; int dp[MAXN][MAXN]; int d[MAXN]; int solve(int l, int r) { if(dp[l][r] != -1) return dp[l][r]; dp[l][r] = solve(l, l + 1) + solve(l + 1, r) + d[r] - d[l]; for(int i = l + 2 ; i < r ; i++) dp[l][r] = min(dp[l][r], solve(l, i) + solve(i, r) + d[r] - d[l]); return dp[l][r]; } int main() { int l, n; while(scanf("%d", &l) != EOF && l){ scanf("%d", &n); memset(dp, -1, sizeof(dp)); d[0] = 0; for(int i = 1 ; i <= n ; i++){ scanf("%d", &d[i]), dp[i - 1][i] = 0; } dp [n + 1] = 0; d[++n] = l; printf("The minimum cutting is %d.\n", solve(0, n)); } return 0; } UVA 562 背包问题,看最后组成方案中最接近且小于sum/2的值是多少,转化一下即可出答案。 sum表示所有硬币值得和。 #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 50000 + 5; int d[MAXN]; int dp[MAXN]; int main() { int t; scanf("%d", &t); while(t--){ int n; scanf("%d", &n); int sum = 0; for(int i = 0 ; i < n ; i++) scanf("%d", &d[i]), sum += d[i]; memset(dp, -1, sizeof(dp)); dp[0] = 1; for(int i = 0 ; i < n ; i++){ for(int j = sum / 2 ; j >= d[i] ; j--){ if(dp[j - d[i]] != -1) dp[j] = 1; } } // for(int i = 0 ; i <= sum / 2 ; i++) // printf("dp[%d] = %d\n", i, dp[i]); int ans = sum; for(int i = sum / 2 ; i >= 0 ; i--){ if(dp[i] != -1){ ans = sum - 2 * i; break; } } printf("%d\n", ans); } return 0; } UVA 348 石子合并问题类似,难点主要在于输出(大模拟) #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; #define LL long long const int MAXN = 10 + 2; int r[MAXN], c[MAXN]; LL dp[MAXN][MAXN]; int pri[MAXN]; int path[MAXN][MAXN]; void solve(int l, int r) { int mark = path[l][r]; // printf("\nl = %d, r = %d, mark = %d\n", l, r, mark); // system("pause"); if(l == r){ printf("A%d", l); return; } if(mark - l > 0) printf("("); solve(l, mark); if(mark - l > 0) printf(")"); printf(" x "); if(r - mark - 1 > 0) printf("("); solve(mark + 1, r); if(r - mark - 1 > 0) printf(")"); } int main() { // freopen("UVA 348.in","r", stdin); int n; int cas = 0; while(scanf("%d", &n) != EOF && n){ for(int i = 1 ; i <= n ; i++) scanf("%d%d", &r[i], &c[i]); memset(dp, -1, sizeof(dp)); for(int i = 1 ; i < n ; i++) dp[i][i + 1] = r[i] * c[i] * c[i + 1], dp[i][i] = 0, path[i][i + 1] = i; for(int k = 2 ; k <= n ; k++){ for(int i = 1 ; i + k <= n ; i++){ dp[i][i + k] = dp[i + 1][i + k] + r[i] * c[i] * c[i + k]; path[i][i + k] = i; for(int j = i + 1 ; j < i + k ; j++){ int temp = dp[i][j] + dp[j + 1][i + k] + r[i] * c[j] * c[i + k]; if(dp[i][i + k] > temp) path[i][i + k] = j, dp[i][i + k] = temp; } } } printf("Case %d: ", ++cas); printf("("); solve(1, n); printf(")"); printf("\n"); } return 0; } UVA 624 题目意思有点难理解,要求选取轨道的值比预计值N小且最接近N。有多种时选取用轨道最多的那种方案。 因为数据比较小而且没有给时间的上限,所以用状压DP做的。 #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cmath> using namespace std; const int MAXN = 20 + 2; int dp[1 << MAXN]; int d[MAXN]; int out[MAXN]; int main() { int n, m; while(scanf("%d", &n) != EOF && n){ scanf("%d", &m); for(int i = 0 ; i < m ; i++) scanf("%d", &d[i]); int sum = 0; int cnt = 0; int ans = 0; for(int i = 1 ; i < (1 << m) ; i++){ if(dp[i] == -1) continue; int tsum = 0, tans = 0; for(int j = 0 ; j < m ; j++){ if(i & (1 << j)) tsum += d[j], tans++; } // printf("i = %d, tsum = %d, tans = %d\n", i, tsum, tans); if(n - tsum >= 0 && n - tsum < n - sum) ans = i, cnt = tans, sum = tsum; else if(n - tsum == n - sum && cnt < tans) cnt = tans, ans = i; } cnt = 0; for(int i = 0 ; i < m ; i++) if(ans & (1 << i)) out[cnt++] = i; for(int i = 0 ; i < cnt ; i++) printf("%d ", d[out[i]]); printf("sum:%d\n", sum); } return 0; } UVA 10130 裸的01背包 #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 1000 + 5; int dp[MAXN * 30]; int w[MAXN], v[MAXN]; int main() { int t; scanf("%d", &t); while(t--){ int n; scanf("%d", &n); int up = 0; for(int i = 0 ; i < n ; i++) scanf("%d%d", &v[i], &w[i]), up += w[i]; memset(dp, 0, sizeof(dp)); dp[0] = 0; for(int i = 0 ; i < n ; i++){ for(int j = up ; j >= w[i] ; j--){ dp[j] = max(dp[j], v[i] + dp[j - w[i]]); } } int ans = 0; int q; scanf("%d", &q); while(q--){ scanf("%d", &up); ans += dp[up]; } printf("%d\n", ans); } return 0; } UVA 531 最长公共子序列,用的string处理每个字符串。 #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> #include <string> using namespace std; const int MAXN = 3500; const int MAXM = 200; string s1[MAXN], s2[MAXN]; int dp[MAXM][MAXM], path[MAXM][MAXM]; string ans[MAXN * 2]; int cnt; void solve(int cnt1, int cnt2) { if(cnt1 == 0 || cnt2 == 0) return; if(path[cnt1][cnt2] == 0) solve(cnt1 - 1, cnt2 - 1); else if(path[cnt1][cnt2] == 1) solve(cnt1 - 1, cnt2); else if(path[cnt1][cnt2] == -1) solve(cnt1, cnt2 - 1); if(path[cnt1][cnt2] == 0) ans[cnt++] = s1[cnt1]; } int main() { int cnt1, cnt2; cnt1 = cnt2 = 0; while(cin>>s1[++cnt1] != NULL){ if(s1[cnt1][0] != '#') while(cin>>s1[++cnt1] && s1[cnt1][0] != '#'); while(cin>>s2[++cnt2] && s2[cnt2][0] != '#'); cnt1--, cnt2--; memset(dp, 0, sizeof(dp)); for(int i = 1 ; i <= cnt1; i ++){ for(int j = 1 ; j <= cnt2 ; j++){ if(s1[i] == s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1, path[i][j] = 0; else if(dp[i][j - 1] > dp[i - 1][j]) dp[i][j] = dp[i][j - 1], path[i][j] = -1; else dp[i][j] = dp[i - 1][j], path[i][j] = 1; } } cnt = 0; solve(cnt1, cnt2); for(int i = 0 ; i < cnt ; i++){ cout << ans[i]; if(i == cnt - 1) printf("\n"); else printf(" "); } cnt1 = cnt2 = 0; } return 0; } UVA 10456 只有两个物品的完全背包 #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 10000 + 5; int dp[MAXN]; int main() { int n, m, t; while(scanf("%d%d%d", &n, &m, &t) != EOF){ memset(dp, -1, sizeof(dp)); dp[0] = 0; for(int i = 0 ; i < MAXN ; i++){ if(i + n > t) break; if(dp[i] != -1){ dp[i + n] = max(dp[i + n], dp[i] + 1); } } for(int i = 0 ; i < MAXN ; i++){ if(i + m > t) break; if(dp[i] != -1){ dp[i + m] = max(dp[i + m], dp[i] + 1); } } int ans = 0; int beer = t; int ok = 0; int ok2 = 0; for(int i = t ; i >= 0 ; i--){ if(dp[i] != -1){ ans = dp[i]; if(i == t) ok = 1; ok2 = 1; beer = t - i; break; } } if(ok == 1) printf("%d\n", ans); else printf("%d %d\n", ans, beer); } return 0; } UVA 10285 记忆化+dp #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 100 + 5; int g[MAXN][MAXN], dp[MAXN][MAXN]; int dx[] = {-1, 0, 1, 0}; int dy[] = {0, -1, 0, 1}; char name[MAXN]; int n, m; int valid(int x, int y) { if(x < 1 || x > n) return false; if(y < 1 || y > m) return false; return true; } int solve(int x, int y) { if(dp[x][y] != -1) return dp[x][y]; dp[x][y] = 1; for(int i = 0 ; i < 4 ; i++){ int tx = dx[i] + x; int ty = dy[i] + y; if(valid(tx, ty) && g[tx][ty] > g[x][y]) dp[x][y] = max(dp[x][y], solve(tx, ty) + 1); } return dp[x][y]; } int main() { int t; scanf("%d", &t); while(t--){ scanf("%s", name); scanf("%d%d", &n, &m); for(int i = 1 ; i <= n ; i++) for(int j = 1 ; j <= m ; j++) scanf("%d", &g[i][j]); memset(dp, -1, sizeof(dp)); int ans = 1; for(int i = 1 ; i <= n ; i++) for(int j = 1 ; j <= m ; j++) ans = max(ans, solve(i, j)); printf("%s: %d\n", name, ans); } return 0; } UVA 437 排序后往后DP即可。 #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> using namespace std; const int MAXN = 30 * 6; int dp[MAXN]; struct D { int x, y, z; D(){} D(int _x, int _y, int _z){x = _x, y = _y, z = _z;} }d[MAXN]; bool cmp(D a, D b) { if(a.x != b.x) return a.x > b.x; if(a.y != b.y) return a.y > b.y; return a.z > b.z; } int main() { // freopen("UVA 437.in", "r", stdin); int n; int cas = 0; while(scanf("%d", &n) != EOF && n){ for(int i = 0 ; i < n ; i++){ scanf("%d%d%d", &d[i * 6].x, &d[i * 6].y, &d[i * 6].z); d[i * 6 + 1] = D(d[i * 6].x, d[i * 6].z, d[i * 6].y); d[i * 6 + 2] = D(d[i * 6].y, d[i * 6].x, d[i * 6].z); d[i * 6 + 3] = D(d[i * 6].y, d[i * 6].z, d[i * 6].x); d[i * 6 + 4] = D(d[i * 6].z, d[i * 6].x, d[i * 6].y); d[i * 6 + 5] = D(d[i * 6].z, d[i * 6].y, d[i * 6].x); } n *= 6; sort(d, d + n, cmp); for(int i = 0 ; i < n ; i++) dp[i] = 0; int ans = 0; for(int i = 0 ; i < n ; i++){ dp[i] += d[i].z; ans = max(ans, dp[i]); for(int j = i + 1 ; j < n ; j++){ if(d[i].x > d[j].x && d[i].y > d[j].y) dp[j] = max(dp[i], dp[j]); } } // printf("/////*****n = %d***////\n", n); // for(int i = 0 ; i < n ; i++) // printf("x = %d, y = %d, z = %d, dp[%d] = %d\n", d[i].x, d[i].y, d[i].z, i, dp[i]); printf("Case %d: maximum height = %d\n", ++cas, ans); } return 0; } UVA 825 题面好奇怪。 就是一个地图有坏点不能走,问从(1,1)走到(n,m)的方案数。 #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> #include <string> using namespace std; const int MAXN = 1000 + 5; long long dp[MAXN][MAXN]; int g[MAXN][MAXN]; char s[MAXN]; int main() { int t; scanf("%d", &t); int f = 1; while(t--){ int n, m; scanf("%d%d", &n, &m); memset(dp, 0, sizeof(dp)); memset(g, 0, sizeof(g)); for(int i = 1; i <= n ; i++){ int u; scanf("%d", &u); cin.getline(s, MAXN); int temp = 0; for(int j = 0 ; j < (int)strlen(s) ; j++){ if(s[j] == ' '){ g[u][temp] = -1; temp = 0; } else temp = temp * 10 + s[j] - '0'; } if(temp != 0) g[u][temp] = -1; } if(f) f = 0; else printf("\n"); if(g[1][1] == -1 || g [m] == -1){ printf("0\n"); continue; } dp[1][1] = 1; for(int i = 1 ; i <= n ; i++){ for(int j = 1 ; j <= m ; j++){ if(g[i][j] == -1) continue; dp[i][j + 1] += dp[i][j]; dp[i + 1][j] += dp[i][j]; } } printf("%lld\n", dp [m]); } return 0; } UVA 10069 dp[i]表示表示在字符串Z中到i结尾的种类多少个。 按照顺序遍历S字符串,按照倒序遍历Z字符串,就把问题转化成一个类似于01背包的问题。 作死用java写的,主要是字符串处理。String.AtChar(int pos)可以访问第i位的字符,cin.NextLine()可以完成输出。 交文件的时候把package注释掉,第一个public class后面接Main //package uva10069; import java.io.*; import java.math.*; import java.text.*; import java.util.*; //import java.io.BufferedReader; //import java.io.IOException; //import java.io.InputStreamReader public class Main { public static void main(String[] args) { Scanner cin = new Scanner(new BufferedInputStream(System.in)); // BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in)); int t; t = cin.nextInt(); String s1 = cin.nextLine(); while(t > 0){ t--; s1 = cin.nextLine(); String s2 = cin.nextLine(); int l1 = s1.length(); int l2 = s2.length(); if(l2 == 0){ System.out.println("1\n"); continue; } // char[] s1 = t1.charAt(0); // char[] s2 = t2.charAt(0); BigInteger[] dp; dp = new BigInteger[1000]; BigInteger one = BigInteger.valueOf(1); for(int i = 0 ; i < l2 ; i++) dp[i] = BigInteger.valueOf(0); // System.out.println("t1 = " + t1 + "\nt2 = " + t2 + "\n"); // System.out.println("s1 = " + s1 + "\ns2 = " + s2 + "\n"); for(int i = 0 ; i < l1 ; i++){ for(int j = l2 - 1 ; j >= 0 ; j--){ if(s1.charAt(i) == s2.charAt(j)){ // System.out.println("i = " + i + " j = " + j + "\n"); if(j == 0) dp[j] = dp[j].add(one); else dp[j] = dp[j].add(dp[j - 1]); } } } // for(int i = 0 ; i < l1 ; i++){ // System.out.println("s1.Atchar[" + i + "] = " + s1.charAt(i) + "\n"); // } // for(int i = 0 ; i < l2 ; i++) // System.out.println("dp[" + i + "] = " + dp[l2 - 1] + "\n"); System.out.println(dp[l2 - 1]); // System.out.println("\n"); } } } UVA 10534 最长上升子序列的变形。 #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> #include <string> using namespace std; const int MAXN = 10000 + 5; int dpl[MAXN], dpr[MAXN]; int d[MAXN]; int l[MAXN], r[MAXN]; int main() { int n; while(scanf("%d", &n) != EOF){ for(int i = 0 ; i < n ; i++) scanf("%d", &d[i]); int cnt = 0; l[0] = 0; for(int i = 0 ; i < n ; i++){ if(d[i] > l[cnt]){ l[++cnt] = d[i]; dpl[i] = cnt; } else{ int mark = lower_bound(l, l + cnt, d[i]) - l; l[mark] = min(l[mark], d[i]); dpl[i] = mark; } } cnt = 0; for(int i = n - 1 ; i >= 0 ; i--){ if(d[i] > l[cnt]){ l[++cnt] = d[i]; dpr[i] = cnt; } else{ int mark = lower_bound(l, l + cnt, d[i]) - l; l[mark] = min(l[mark], d[i]); dpr[i] = mark; } } // printf("dpl\n"); // for(int i = 0 ; i < n ; i++) // printf("%d ", dpl[i]); // printf("dpl\n"); // printf("dpr\n"); // for(int i = 0 ; i < n ; i++) // printf("%d ", dpr[i]); // printf("dpr\n"); int ans = 0; for(int i = 0 ; i < n ; i++) ans = max(ans, min(dpl[i], dpr[i]) * 2 - 1); printf("%d\n", ans); } return 0; } UVA 10051 搞清楚状态转移就行,比如用这个重量的front的dp值去更新重量更大的方块的back的dp值,具体用异或处理一下就可以。数组开小WA了几次。 #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <iostream> #include <string> #include <vector> using namespace std; const int MAXN = 3000 + 5; int dp[MAXN * 6]; int path[MAXN * 6]; int d[MAXN][6]; vector<int>lin[105]; int x[MAXN], y[MAXN]; int main() { int n; int cas = 0; while(scanf("%d", &n) != EOF && n){ for(int i = 0 ; i <= 100 ; i++) lin[i].clear(); for(int i = 0 ; i < n ; i++){ for(int j = 0 ; j < 6 ; j++){ scanf("%d", &d[i][j]), dp[i * 6 + j] = 1; path[i * 6 + j] = i * 6 + j; lin[d[i][j]].push_back(i * 6 + j); } } int ans = 0; int mark = 0; for(int i = 0 ; i < n ; i++){ for(int j = 0 ; j < 6 ; j++){ int now = (i * 6 + (j ^ 1)); int k = lower_bound(lin[d[i][j]].begin(), lin[d[i][j]].end(), now) - lin[d[i][j]].begin(); for(; k < (int)lin[d[i][j]].size() ; k++){ int ne = lin[d[i][j]][k]; if(ne / 6 <= now / 6) continue; // if(i == 0 && j == 0){ // printf("now = %d, ne = %d\n", now, ne); // } if(dp[ne] < dp[now] + 1){ dp[ne] = dp[now] + 1; path[ne] = now; } } if(dp[now] > ans){ ans = dp[now], mark = now; } } } int cnt = 0; while(1){ x[cnt] = mark / 6, y[cnt++] = mark % 6; if(path[mark] == mark) break; mark = path[mark]; } if(cas != 0) printf("\n"); printf("Case #%d\n", ++cas); printf("%d\n", ans); for(int i = cnt - 1 ; i >= 0 ; i--){ printf("%d ", x[i] + 1); if(y[i] == 0) printf("front\n"); else if(y[i] == 1) printf("back\n"); else if(y[i] == 2) printf("left\n"); else if(y[i] == 3) printf("right\n"); else if(y[i] == 4) printf("top\n"); else if(y[i] == 5) printf("bottom\n"); } // printf("\n"); } return 0; } /* 3 1 2 2 2 1 2 3 3 3 3 3 3 3 2 1 1 1 1 10 1 5 10 3 6 5 2 6 7 3 6 9 5 7 3 2 1 9 1 3 3 5 8 10 6 6 2 2 4 4 1 2 3 4 5 6 10 9 8 7 6 5 6 1 2 3 4 7 1 2 3 3 2 1 3 2 1 1 2 3 0 */ UVA 10651 用状压DP的方式模拟+记忆化就可以。
#include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #include <cmath> #include <string> using namespace std; const int MAXN = 13; int dp[1<<MAXN]; char str[20]; int solve(int s) { if(dp[s] != -1) return dp[s]; int val = 0; for(int i = 0 ; i < 12 ; i++) if((1 << i) & s) val++; dp[s] = val; for(int i = 0 ; i < 12 ; i++){ if((s & (1 << i))){ if(i > 1 && (s & (1 << (i - 1))) && !(s & (1 << (i - 2)))){ int ts = (s ^ (1 << (i - 2)) ^ (1 << (i - 1)) ^ (1 << (i))); dp[s] = min(dp[s], solve(ts)); } if(i < 10 && (s & (1 << (i + 1))) && !(s & (1 << (i + 2)))){ int ts = (s ^ (1 << (i + 2)) ^ (1 << (i + 1)) ^ (1 << (i))); dp[s] = min(dp[s], solve(ts)); } } } return dp[s]; } int main() { memset(dp, -1, sizeof(dp)); int t; scanf("%d", &t); while(t--){ scanf("%s", str); int ts = 0; for(int i = 11 ; i >= 0 ; i--){ if(str[i] == 'o') ts += (1 << i); } printf("%d\n", solve(ts)); } return 0; }
相关文章推荐
- GET请求的中文乱码问题及处理意义
- AutoFac记录
- c#简单实现记事本功能
- 高级:2015年10月19日作业
- python下安装numpy、matplotlib、scipy过程
- 九度OJ 1115:数字求和 (基础题)
- Python 书籍推荐
- 九度OJ 1115:数字求和 (基础题)
- PHP:6种方法获取文件的扩展名
- 10001---Ajax定义与原理
- JAVA异常架构图及面试题
- 一,$符号的由来
- Mahout学习之聚类算法Kmeans
- Douglas Crockford 大神写的 JavaScript 异步控制库:RQ(上)
- hdu5282 最长公共子序列
- 高级:2015年10月23日作业
- iOS开发常见error
- Android网络通信框架LiteHttp:简介和教学大纲
- 一个游戏中的条件概率问题
- 机器学习(十一)机器学习系统设计的细节问题