[程序设计与算法(2)][动态规划]第五周第二题解题报告: Zipper

题目链接:http://cxsjsxmooc.openjudge.cn/2017t2springhw5/2/

----------------------------------------------题目------------------------------------------------------

描述

Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.

For example, consider forming "tcraete" from "cat" and "tree":

String A: cat
String B: tree
String C: tcraete

As you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming "catrtee" from "cat" and "tree":

String A: cat
String B: tree
String C: catrtee

Finally, notice that it is impossible to form "cttaree" from "cat" and "tree".
输入The first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line.

For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.
输出For each data set, print:

Data set n: yes

if the third string can be formed from the first two, or

Data set n: no

if it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.
样例输入

3
cat tree tcraete
cat tree catrtee
cat tree cttaree

样例输出

Data set 1: yes
Data set 2: yes
Data set 3: no

-------------------------------------------------题解------------------------------------------------------

本题是一道DP的题目,核心问题就是“状态”。

我假设有i, j, k三个光标分别指向s1[i], s2[j], s3[k]的位置。

那么对于cat[0] tree[0] tcraete[0], 对于s3的t字符,必须从s2[0]位置拿走,本问题转化为: cat[0] tree[1] tcraete[1]

依次进行,直到

cat\0[3] tree\0[4] tcraete\0[7]

对于样例3,cat tree cttaree字符串进行上述模拟,在

cat[1] tree[1] cttaree[2]时,发现s3字符串的当前字符无法从s1,s2中对应光标进行匹配。

由此可以看出,当k光标可以走到s3字符的末尾,则代表s3字符可以由s1 s2组成。

对于样例2,存在一种情况:

当光标读到cat[2] tree[0] catrtee[2]时,即可以读s1的't',也可以读s2的't',存在岔路。

在这种情况下,我们需要对两条路都进行试探,而两条路得到的解(true/false)中只要有一条能通,本样例就应该输出Yes,因此是“或”关系。

此外,i, j, k中,k=i+j,因此本题的dp状态为二维。即solve(i,j)

在代码实现中,通过建立dp数组来记录已经计算过的路径,保证每个状态(i, j)最多被访问一次。(当s1 s2中出现大量岔路的情况,不做状态记录处理会产生大量的重复递归调用,严重超时)。

实现代码如下: 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 #define DEBUG 0
 6 
 7 using namespace std;
 8 
 9 char s1[500], s2[500], s3[500];
10 int s3_len;
11 int dp[500][500];
12 
13 void reset_dp() {
14     for (int i = 0; i < 500; ++i)
15         for (int j = 0; j < 500; ++j)
16             dp[i][j] = -1;
17 }
18 
19 bool solve(int i, int j, int k) {
20     if (dp[i][j] != -1) {
21         return dp[i][j];
22     }
23     if (k == s3_len) {
24         dp[i][j] = 1;
25         return dp[i][j];
26     }
27     if (s1[i] != s3[k] && s2[j] != s3[k]) {
28         dp[i][j] = 0;
29         return dp[i][j];
30     }
31     if (s1[i] == s2[j]) {
32         dp[i][j] = solve(i + 1, j, k + 1) || solve(i, j + 1, k + 1);
33         return dp[i][j];
34     }
35     else if (s1[i] == s3[k])
36         return solve(i + 1, j, k + 1);
37     else
38         return solve(i, j + 1, k + 1);
39 }
40 
41 int main() {
42     int k;
43     cin >> k;
44     for (int i = 1; i <= k; ++i) {
45         cin >> s1 >> s2 >> s3;
46         s3_len = strlen(s3);
47         reset_dp();
48         if (solve(0, 0, 0)) {
49             printf("Data set %d: yes\n", i);
50         }
51         else {
52             printf("Data set %d: no\n", i);
53         }
54     }
55     return 0;
56 }

 通过截图:

原文地址:https://www.cnblogs.com/aweffr/p/6427664.html