sicily 1010. Zipper dfs || dp

//这题可以用暴力搜索

//要注意减枝和各种预处理,不然各种TLE

//方法是搜索s里的=s1的子串,再判断s剩下的字符是否能组成s2



#include <iostream>

#include <cstring>

#include <cstdio>

using namespace std;



const int N = 205;

char  s1[N], s2[N], s[N], tmp[N];

int low_times1[30], low_times2[30], upper_times1[30], upper_times2[30];

int s1_size, s2_size, s_size;

int flag[N+N];



//dfs查找s串里的等于s1的子串

//剩下的按顺序就是s2串

bool dfs(int s1_count,int count)

{

	if (s1_count > s1_size)

		return false;



	int cnt = 0;

	//找出s1串,判断剩下的是否能组成s2串

	if (s1_count == s1_size)

	{

		cnt = count-s1_count;

		for (int i = count; i < s_size; i++)

			if (flag[i] == 0)

			{

				if (s[i] != s2[cnt])

					return false;

				cnt++;

			}



		return true;

	}



	//若s1相邻两个字符所在s的位置为i和j,那么s的i~j之间的组成的字串必须是s2的字串

	//根据这个条件减枝

	for (int i = 0; i < count; i++)

		if (flag[i] == 0)

		{

			if (s[i] != s2[cnt])

				return false;

			cnt++;

		}



	for (int i = count; i < s_size; i++)

		if (s1[s1_count] == s[i])

		{

			flag[i] = 1;



			if (dfs(s1_count+1, i+1))

				return true;



			flag[i] = 0;

		}



	return false;

}



int main()

{

	int cases;

	int num = 0;



	scanf("%d", &cases);

	while (cases--)

	{

		num++;

		memset(flag, 0, sizeof(flag));

		memset(low_times1, 0, sizeof(low_times1));

		memset(upper_times2, 0, sizeof(upper_times2));

		memset(upper_times1, 0, sizeof(upper_times1));

		memset(low_times2, 0, sizeof(low_times1));



		scanf("%s%s%s", s1, s2, s);



		s1_size = strlen(s1);

		s2_size = strlen(s2);

		s_size = s1_size + s2_size;

		if (s1_size > s2_size)

		{

			strcpy(tmp, s1);

			strcpy(s1, s2);

			strcpy(s2, tmp);

			swap(s1_size, s2_size);

		}



		for (int i = 0; i < s1_size; i++)

			if (s1[i] >= 'a' && s1[i] <= 'z')

				low_times1[s1[i]-'a']++;

			else

				upper_times1[s1[i] - 'A']++;



		for (int i = 0; i < s2_size; i++)

			if (s2[i] >= 'a' && s2[i] <= 'z')

				low_times1[s2[i]-'a']++;

			else

				upper_times1[s2[i]-'A']++;



		for (int i = 0; i < s_size; i++)

			if (s[i] >= 'a' && s[i] <= 'z')

				low_times2[s[i]-'a']++;

			else

				upper_times2[s[i] - 'A']++;



		//先预处理

		//s的字符出现个数应 = s1字符出现个数+s2字符个数

		bool ans = true;

		for (int i = 0; i < 26; i++)

			if (low_times1[i] != low_times2[i] || upper_times1[i] != upper_times2[i])

			{

				ans = false;

				break;

			}



			if (!ans)

			{

				printf("Data set %d: no\n", num);

				continue;

			}



			if (dfs(0, 0))

				printf("Data set %d: yes\n", num);

			else

				printf("Data set %d: no\n", num);		

	}

	return 0;

}

 

 

 

//后来发现原来可以直接dp

//设dp[i][j]为a串的前i个字符和b串的前j个字符能否组成c的i+j个字符

//dp[i][j] = (dp[i-1][j] && c[i+j] == a[i]) || (dp[i][j-1] && c[i+j] = b[j])

#include <iostream>

#include <string>

#include <cstring>

using namespace std;



const int N = 205;



string a, b, c;

bool dp[N][N];



int main()

{

	int cases;

	int num = 0;



	cin >> cases;



	while (cases--)

	{

		num++;

		cin >> a >> b >> c;



		memset(dp, false, sizeof(dp));



		dp[0][0] = true;



		for (int i = 0; i < b.size(); i++)	

			if (b[i] == c[i])

				dp[0][i+1] = true;

			else

				break;

	

		for (int i = 0; i < a.size(); i++)	

			if (a[i] == c[i])

				dp[i+1][0] = true;

			else

				break;

		

		for (int i = 1; i <= a.size(); i++)

			for (int j = 1; j <= b.size(); j++)

				dp[i][j] = (dp[i-1][j] && c[i+j-1] == a[i-1]) || (dp[i][j-1] && c[i+j-1] == b[j-1]);

	

		if (dp[a.size()][b.size()])

			cout << "Data set "<< num << ": yes" << endl;

		else

			cout << "Data set "<< num << ": no" << endl;

	}

	return 0;

}

你可能感兴趣的:(zip)