POJ动态规划练习(计划6-8题)

Problems

POJ2192 - Zipper

POJ1717 - Dominoes

 

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 }
View Code

 

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 }
View Code

 

posted @ 2016-07-22 19:50  二和鶏  阅读(215)  评论(0编辑  收藏  举报