http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1796
RunID | User | Problem | Result | Time(MS) | Memory(K) | Length | Language | Submit Time |
---|---|---|---|---|---|---|---|---|
871829 | Code123 | 1796 | Accepted | 7 | 256 | 2357 | GCC | 2012-1-8 0:46:22 |
Preparing for CET 6
Time Limit:50MS Memory Limit:32768K
Description:
英语6级就要开考了,可是Fatboy连单词都还没有背,这下可把他急坏了。于是他只好拿出单词册来,开始背单词。 背了一段时间后,Fatboy发现了一个背单词的高效方法。当把单词头尾相接串成一组单词后,可以一下子把串起来的所有单词都记住。比如:fatboy yard derv vivid ,这4个单词每个单词的头字母都与前一个单词的尾字母相同,那么Fatboy就可以一下子记住这4个单词。Fatboy拿着单词册,产生了一个疑问: “如果只串一次,我最多可以背多少单词呢?” 下面就请你编个程序来帮助他解决这个问题,记住:每个单词只能用一次,单词串接时单词出现的先后顺序必须和单词册中单词出现的先后顺序一样。如:假如单词册中单词出现的顺序是:12345 ,那么单词串接顺序不能是:5421或5134,而134则是一个合法串接。Input:
每组数据第一行为数N(1≤N≤200),表示单词册里有多少个单词,紧接的N行按单词在单词册中出现顺序给出单词,输入文件以一个0表示结尾。Output:
对应每一组单词输出一个M,表示Fatboy最多可以记住多少单词。每个输出占一行。Sample Input:
4 fatboy yard derv vivid 5 fatboy yard derv vivid uinque 2 apple orange 0
Sample Output:
4 4 1
Source:
Fatboy-------------------------------
思路:
1. 由于单词只能用一次,要考虑单词重复问题。
2. 顺序只能从头到尾,不能乱序。
构造结构体如下:
#define CH_MAX 256
#define WORD_LENGTH 256
typedef struct word_t{
char word[WORD_LENGTH];
char length;
char isUsed;
int next;
} WORD_TYPE, * LPWORD_TYPE;
next 用来串联所有一样的单词,减少比较的次数。
单词的比较方法,拿来判断两个单词是否一样:
int compare(char *srcStr, char *tagStr) {
while (*srcStr == *tagStr && *tagStr != '\0' && *srcStr != '\0') {
srcStr++;
tagStr++;
}
return (*tagStr == *tagStr && *tagStr == '\0') ? 1 : 0;
}
int WORDCompare(LPWORD_TYPE src, LPWORD_TYPE tag){
if (src->length == tag->length)
return compare(src->word, tag->word);
else
return 0;
}
做完之后,就要开始填数据了。
while (EOF != scanf("%d%*c", &g_iCount) && g_iCount != 0) {
for (i = 0; i < g_iCount; i++) {
j = 0;
WordList[i].word[j] = getchar();
while ('\n' != WordList[i].word[j]) {
j++;
while (' ' == (WordList[i].word[j] = getchar())); //这句空格剔除去掉就WA,可以看出每条测试数据后面还有空格,这就是题目的悲催之处,OJ上这种问题挺多的。
}
WordList[i].word[j] = '\0';
WordList[i].isUsed = 0;
WordList[i].length = j;
WordList[i].next = -1;
}
for (i = 0; i < g_iCount; i++) { //把所有一样的单词串联一起
int k = i;
for (j = k + 1; j < g_iCount; j++) {
if (WORDCompare(&WordList[k], &WordList[j])) {
WordList[k].next = j;
k = j;
}
}
}
result = 0;
for (i = 0; i< g_iCount; i++) { //这里写的比较罗嗦。
int k = WordList[i].next;
while (k != -1) { //把所有和第一个单词一样的单词都标记为已经被使用。
WordList[k].isUsed = 1;
k = WordList[k].next;
}
if (result < (tempResult = deep(WordList[i].word[ WordList[i].length - 1 ], i + 1))) {
result = tempResult;
}
k = WordList[i].next;
while (k != -1) {//这里在上面的搜索结束之后恢复原样。
WordList[k].isUsed = 0;
k = WordList[k].next;
}
}
printf("%d\n", result == 0 ? 1 : result);
}
搜索方法:
int deep(char tp, int k)
{
int j, i, tempResult, result = 0;
if (k >= g_iCount)
return 1;
for (i = k; i < g_iCount; i++) {
int k = WordList[i].next;
if (WordList[i].isUsed) { //被使用了就跳过
continue;
}
while (k != -1) { //否则做同样的事情,和第一个单词一样的单词都做标记
WordList[k].isUsed = 1;
k = WordList[k].next;
}
if (!WordList[i].isUsed && tp == WordList[i].word[0]) {
if ( result < (tempResult = deep(WordList[i].word[ WordList[i].length - 1 ], i + 1) ) ) {
result = tempResult;
}
}
k = WordList[i].next;
while (k != -1) {//回复
WordList[k].isUsed = 0;
k = WordList[k].next;
}
}
return result + 1;
}