题目:给你一些字符串,问哪些字符串不是其他字符串的子集,字符串的集合为字母组成的重集。
分析:字符串,dancing-links。Knuth有一篇关于dancing-links的论文,讲述关于搜索的优化。
在搜索时,将所有的状态建立一个链表,表之间的状态建立相互关系。
每次搜索时,进行剪枝,将不成立的节点从链表中删掉,回溯时在拼上去。
用数组建立链表,高效方便,存储L,R左右两端下标即可。
本题直接进行删除即可。
如果,一个字符串的补集是另一个字符串的子集,这个字符串的集合一定是另一的超集。
解法:
1.对每个字符串求补集(每个字符的个数记成负的即可)。
2.对补集排序,然后向后扫描,扫到他的子集(补集的超级)就删除那个节点。
3.重新排序,输出。
说明:看到有人用字典树做的,每次插入的时候先查询。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
typedef struct noded
{
char word[11];
int used;
}dnode;
dnode s[15005];
int L[15005];
int R[15005];
int id[15005];
int sum[15005][27];
using namespace std;
int cmp1( const void* a, const void* b )
{
int l1 = strlen(((dnode *)a)->word);
int l2 = strlen(((dnode *)b)->word);
if ( l1 == l2 )
return strcmp( ((dnode *)b)->word, ((dnode *)a)->word );
return l2 - l1;
}
int cmp2( const void* a, const void* b )
{
if ( ((dnode *)b)->used == ((dnode *)a)->used )
return strcmp( ((dnode *)a)->word, ((dnode *)b)->word );
return ((dnode *)a)->used - ((dnode *)b)->used;
}
int main()
{
int count = 1;
while ( gets(s[count].word) ) {
if ( !strlen(s[count].word) ) break;
s[count ++].used = 0;
}
qsort( s+1, count-1, sizeof(s[0]), cmp1 );
memset( sum, 0, sizeof(sum) );
for ( int i = 1 ; i < count ; ++ i )
for ( int j = 0 ; s[i].word[j] ; ++ j )
sum[i][s[i].word[j]-'a'] --;
for ( int i = 1 ; i < count ; ++ i ) {
id[i] = i;
L[i] = i-1;
R[i] = i+1;
}
R[0] = 1;
R[count-1] = 0;
for ( int p = R[0] ; p ; p = R[p] )
for ( int q = R[p] ; q ; q = R[q] ) {
int flag = 1;
for ( int k = 0 ; k < 26 ; ++ k )
if ( sum[id[p]][k] > sum[id[q]][k] ) {
flag = 0;
break;
}
if ( flag ) {
s[id[q]].used = 1;
R[L[q]] = R[q];
L[R[q]] = L[q];
}
}
qsort( s+1, count-1, sizeof(s[0]), cmp2 );
for ( int i = 1 ; i < count ; ++ i )
if ( s[i].used ) break;
else printf("%s\n",s[i].word);
//system("pause");
return 0;
}