写在前面
这道题是我以前做的,回顾这道题的时候觉得这道题好就写了一篇。
题目描述
一组单词是安全的,当且仅当不存在一个单词是另一个单词的前缀,这样才能保证数据不容易被误解。现在你手上有一个单词集合 ,你需要计算有多少个子集是安全的。
注意空集永远是安全的。
输入格式
第一行一个数 ,表示集合的大小,以下 行。每行一个由构成 的字符串。
输出格式
安全子集的个数。
样例
输入
3
hello
hell
hi
输出
6
分析
首先,我们需要定义一个
数组
来表示
是否为
的前缀。不妨将每个单词按字典序从小到大排序,
函数更新
数组。
定义
为 包含第
个单词的子集总数,因为前面已经排了序,容易想出
。
代码
#include <cstdio>
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 55;
struct Node {
char a[MAXN];
int len;
}arr[MAXN];
bool cmp(Node x, Node y) {
for(int i = 0; i < max(x.len, y.len); i ++) {
if(x.a[i] > y.a[i]) return 0;
else if(x.a[i] < y.a[i]) return 1;
}
return 0;
}
bool f[MAXN][MAXN];
bool Find_bol(int x, int y) {
for(int i = 0; i < min(arr[x].len, arr[y].len); i ++) {
if(arr[x].a[i] != arr[y].a[i]) return 0;
}
return 1;
}
LL dp[MAXN];
int main() {
int n;
LL sum = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%s", arr[i].a);
arr[i].len = strlen(arr[i].a);
dp[i] = 1;
}
sort(arr + 1, arr + 1 + n, cmp);
for(int i = 1; i <= n; i ++) {
for(int j = 1; j < i; j ++) {
f[i][j] = Find_bol(i, j);
}
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j < i; j ++) {
if(!f[i][j]) {
dp[i] += dp[j];
}
}
}
for(int i = 1; i <= n; i ++) {
sum += dp[i];
}
printf("%lld", sum + 1);
return 0;
}