POJ动态规划练习(计划6-8题)
Problems
Solutions
POJ2192 - Zipper
题目大意:给定字符串s1, s2和s,问s1和s2是否满足:均为s的子序列(不必连续)且恰能拼成s(len(s1), len(s2)<=200)。
为方便设字符串下标从1开始。用布尔变量dp[i][j]表示s1[1..i]和s2[1..j]能否拼成s[1..i+j],显然s[i+j]只能是s1[i]和s2[j]中的一个(即最优子结构),由此可以写出状态转移方程。边界条件为dp[0][0] = 1。时间复杂度为O(L2)。
1 // Problem: poj2192 - Zipper 2 // Category: Dynamic programming 3 // Author: Niwatori 4 // Date: 2016/07/22 5 6 #include <iostream> 7 #include <cstring> 8 #include <string> 9 using namespace std; 10 11 int main() 12 { 13 int t; cin >> t; 14 for (int i = 1; i <= t; ++i) 15 { 16 string s1, s2, s; 17 cin >> s1 >> s2 >> s; 18 int len1 = s1.length(), len2 = s2.length(); 19 s1 = ' ' + s1; s2 = ' ' + s2; s = '*' + s; // For convenience 20 21 bool dp[205][205]; 22 memset(dp, 0, sizeof(dp)); 23 dp[0][0] = 1; 24 for (int i = 0; i <= len1; ++i) 25 for (int j = 0; j <= len2; ++j) 26 { 27 if (s1[i] == s[i + j]) 28 dp[i][j] = dp[i][j] || dp[i - 1][j]; 29 if (s2[j] == s[i + j]) 30 dp[i][j] = dp[i][j] || dp[i][j - 1]; 31 } 32 cout << "Data set " << i << ": " << (dp[len1][len2] ? "yes" : "no") << endl; 33 } 34 return 0; 35 }
POJ1717 - Dominoes
题目大意:给定N个整数对(x, y),允许交换整数对的内部顺序(即变为(y, x))。求最少的交换次数,使得交换后它们的横坐标和与纵坐标和的绝对值之差最小(N<=1,000,0<=x, y<=6)。
所有横纵坐标的总和是一定的,所以我们不妨只考虑横坐标的情形。用dp[i][j]表示前i个整数对使得横坐标和为j的最小交换次数,每加进来一个整数对(x, y),考虑是否将其交换,就可以对dp[i+1][j+x]和dp[i+1][j+y]进行更新。注意到每次状态转移只与前一次转移的结果有关,所以可以利用滚动数组节省空间。最后通过枚举横坐标的和来枚举gap,找到最小的合法答案输出即可。时间复杂度约为O(6N2)。
1 // Problem: poj1717 - Dominoes 2 // Category: Dynamic programming 3 // Author: Niwatori 4 // Date: 2016/07/24 5 6 #include <stdio.h> 7 #include <string.h> 8 #define MAXS 12010 9 #define INF 0x3f3f 10 #define MIN(a,b) ((a)<(b)?(a):(b)) 11 12 int main() 13 { 14 int n, x, y, sum = 0, ans; 15 int dp[MAXS], dp1[MAXS]; 16 scanf("%d", &n); 17 18 memset(dp, INF, sizeof(dp)); 19 memset(dp1, INF, sizeof(dp1)); 20 dp[0] = 0; 21 for (int i = 0; i < n; ++i) 22 { 23 scanf("%d%d", &x, &y); 24 sum += (x + y); 25 for (int j = 0; j <= sum; ++j) // State transition from dp to dp1 26 { 27 dp1[j + x] = MIN(dp[j], dp1[j + x]); 28 dp1[j + y] = MIN(dp[j] + 1, dp1[j + y]); 29 } 30 memcpy(dp, dp1, sizeof(dp1)); // Rolling array 31 memset(dp1, INF, sizeof(dp1)); 32 } 33 34 for (int i = sum / 2; i <= sum; ++i) // Enumerate the gap through sumx 35 if (dp[i] < INF || dp[sum - i] < INF) 36 { 37 ans = MIN(dp[i], dp[sum - i]); 38 break; 39 } 40 printf("%d", ans); 41 return 0; 42 }