• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

  • 联系
  • 订阅
  • 管理

View Post

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;
}

posted on 2011-04-08 21:15  sysuwhj  阅读(692)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3