UVA12249 Overlapping Scenes 题解

\(\Large \text{题面}\)

题目大意

共有 \(T\) 组数据。

每组数据会给出一个整数 \(n\),以及 \(n\) 个字符串。

现在将这 \(n\) 个字符串以任意顺序首尾相接,若有相同的部分可以重合,求操作后得到的字符串的最短长度。

思路

可以看到数据范围非常小(\(T \leq 50, n \leq 6, \text{每个字符串的长度} \leq 10\)),时限也开到了 \(3\) 秒,那么说明此题并不难,考虑暴力一些的解法。

首先,由于是“任意顺序”,所以可以通过 next_permutation 函数求出 \(n\) 个字符串的全排列(即 \(n\) 个字符串的所有排列情况)。

对于每一个“排列”,暴力地判断能否“重合”。具体做法是从第二个字符串开始暴力判断最多能和前一个字符串重合多少。

最后,在每一种“排列”所得到的答案中取最小值即可。

实现

首先要强调的就是多测清空!!!

还有要注意的是在进行“全排列”的操作的时候,初始情况要从“字典序”最小的开始,这样才可以把所有的情况都涉及到。“字典序最小”可以通过 sort 函数来完成。

#include "bits/stdc++.h"

using namespace std;

const int inf = 0x3f3f3f3f;

int T, n;
string s[20], ans;
int res;

int work() {
	ans = s[0];
	for (int i = 1; i < n; i ++ ) {
		int st = min(ans.size(), s[i].size()); // 从两个字符串的长度较短的那个开始
		for (int j = st; j >= 0; j -- ) { // 枚举一遍
			if (ans.substr(ans.size() - j, j) == s[i].substr(0, j)) { // 判断是否可以拼接
				ans += s[i].substr(j, s[i].size() - j);
				break;
			}
		}
	}
	return ans.size(); // 返回长度(即当前情况下的答案)
}

signed main() {
	scanf("%d", &T);
	for (int i = 1; i <= T; i ++ ) {
		scanf("%d", &n);
		for (int i = 0; i < n; i ++ ) cin >> s[i];
		res = inf; // 每次先初始化为最大值,然后再一点点缩减
		sort(s, s + n); // 从“字典序”最小的开始
                        //这样之后经过“全排列”操作就可以把所有的情况都计算上
		do res = min(res, work()); while (next_permutation(s, s + n)); // 对所有的“排列”(即所有情况)进行计算
        // 并且取最小值
		printf("Case %d: %d\n", i, res);
	}
	return 0;
}
posted @ 2023-10-09 14:31  Ifyoung  阅读(3)  评论(0编辑  收藏  举报