2011 ACM/ICPC 大连赛区现场赛题解:Compress the String

Compress the String

Time Limit: 5 Seconds       Memory Limit: 65536 KB

Dan is playing a game with Ben. Ben gives Dan a long string S, and Dan needs to compress S to a list or short strings: s[1]s[2], ..., s[N]S only contains lowercase letters. Each s[i] can contain lowercase letters and digits, but only digits between i+1 and N, inclusive, are allowed for s[i]. For example, when N = 4, allowed digits for s[2] will be '3' and '4'.

In order to decompress such a list of strings into a single string, we'll apply string decompress algorithm for each string one by one, in reverse order (from s[N] to s[1]). The decompressing algorithm for a string is easy: just replace each digit in the string by the corresponding decompressed string with that digit as index. That is to say, for digit i in the string, it will be replaced by the decompressed string s[i]. Because we are applying decompressing algorithm in reverse order, s[i] will always be decompressed before it is used to replace a digit in other strings. When all the strings are decompressed, the decompressed string of s[1] will be the final result. If the decompressing result is S, we say S can be compressed to this list of strings.

Now Ben decides the number of short strings Dan can use (N), as well as the length limit for each short string. Dan needs to decide whether it is possible to compress S to N short strings under this limit.

Input

There are multiple test cases (no more than 150). For each case, there will be three lines. The first line gives an integer N (1 ≤ N ≤ 4), which is the number of short strings Dan can use. The second line gives N integers L[1], ... L[N] (1 ≤ L[i] ≤ 4), which means the length of string s[i] should be at most L[i]. The third line gives the string S. The length of S will be between 1 and 500, inclusive. S will only contain lowercase letters.

Output

For each case, if it is possible to compress S into N strings and the length of each string is no more than the limit, output "Yes". Otherwise, output "No".

Sample Input
1
1
aa
4
4 4 4 4
ttttttttttttttt
Sample Output
No
Yes

Author:  HANG, Hang

Contest: The 2011 ACM-ICPC Asia Dalian Regional Contest


Analysis:

首先,最后的待压缩串的信息只直接和s[1]关联,但是要确定s[1]串的话,又必须要有后面的所有串的信息。

这样搜索的顺序,必须要从后面的串开始,但是这样有没有直接的压缩串的信息,所以剪枝很麻烦。

我的想法就是要在尽量少用剪枝的情况下,通过对搜索结构的优化来达到目的。

权衡之后,我决定采取外层第一曾dfs()仅确定长度和扩展位置,堆每一组合的模糊解,第二层再check()判断其是否有真的合法的方法。


两条剪枝。

1.可行性剪枝:对外层dfs(),记录当前最长的分解串长度。

2.改变搜索顺序:对有解的情况下尽可能发现正解。


代码:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;

#define REP(i, n) for (int i=0;i<int(n);++i)
#define FOR(i, a, b) for (int i=int(a);i<int(b);++i)
#define DWN(i, b, a) for (int i=int(b-1);i>=int(a);--i)
#define DWN_N(i, b, a) for (i=int(b-1);i>=int(a);--i)
#define DWN_1_N(i, b, a) for (i=int(b);i>=int(a);--i)

template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}

const int N = 4, M = 500, L = 4;

char S[M];
int len;
int s[N][L];
int _l[N], l[N], ll[N];
int n;

const int Normal = -1;
bool C[N];
int st[N];
bool check()
{
	RST(C);
	C[n - 1] = true, st[n - 1] = 0;
	DWN(k,n, 1)
		if (C[k])
		{
			int p = st[k];
			REP(i, l[k])
			{
#define j s[k][i]
				if (j == Normal)
				{
					++p;
				}
				else
				{
					if (C[j])
					{
						REP(ii, ll[j])
						{
							if (S[p + ii] != S[st[j] + ii]) return false;
						}
					}
					else
					{
						C[j] = true, st[j] = p;
					}
					p += ll[j];
				}
			}
		}
	return true;
}

inline bool dfs1(int, int);
inline bool dfs2(int, int, int);
bool dfs2(int i, int k, int max_ll)
{
	if (i == l[k])
	{
		ll[k] = 0;
		REP(i, l[k])
			ll[k] += s[k][i] == Normal ? 1 : ll[s[k][i]];
		return dfs1(k + 1, max(max_ll, ll[k]));
	}
	else
	{
		DWN_N(s[k][i], k, -1)
		{
			if (dfs2(i + 1, k, max_ll)) return true;
		}
	}
	return false;
}

bool dfs1(int k = 0, int max_ll = 1)
{
	int t = max_ll;
	FOR(i, k, n) t *= _l[i];
	if (t < len) return false;
	if (k == n)
	{
		return ll[k - 1] == len && check();
	}
	else
	{
		DWN_1_N(l[k], _l[k], 0)
		{
			if (dfs2(0, k, max_ll)) return true;
		}
	}
	return false;
}

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		DWN(i, n, 0) scanf("%d", &_l[i]);
		getchar();
		scanf("%s", S);
		len = strlen(S);
		reverse(S, S + len);
		puts(dfs1() ? "Yes" : "No");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值