对于每一种关系(a是b的前缀字符串),我们可以构建出一条有向边 a->b,
把所有边连起来之后,我们可以得到一个类似于下面的图
会得到一个有多个连通分支的图。转换题意,使得选择某些节点,让任意的两个节点都没有连接关系,且选择的节点最多。
只需把一个连通分量中出度为0的点加入集合就可以了。因为这表示这个点不能成为所有点的前缀。
怎么保证是最多?
证明选择有出度的比没出度的更差就行。选择有出度的,则与他相连的所有点都不能被选取,会导致至少1个无出度和若干有出度的节点不能被选取,而基于构建出来图的特性,可以知道你选择有出度的 <= 选择无出度的 节点的个数。(可以自行验证)
特殊处理: 相同的字符串就没必要处理了。
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int mod = 999911659;
const int N = 1010;
string s[N];
bool check(int i,int j){
if((int)s[i].size() >= (int)s[j].size()) return false;
return s[i] == (s[j].substr(0,(int)s[i].size()));
}
signed main(){
// IOS;
#ifdef ddgo
freopen("C:/Users/asus/Desktop/ddgoin.txt","r",stdin);
#endif
int n;
while(cin>>n && n){
map<string,int> mp,mp1;
int cnt = 0;
for(int i=0;i<n;i++){
string p; cin>>p;
if(!mp[p]) s[cnt++] = p,mp[p] = 1;
}
for(int i=0;i<cnt;i++) //连边,标记有出度的
for(int j=0;j<cnt;j++){
if(i == j) continue;
if(check(i,j)) mp1[s[i]] = 1;
}
int res = 0;
for(int i=0;i<cnt;i++) res += (mp1[s[i]]?0:1);
cout<<res<<endl;
}
return 0;
}