您的位置:首页 > 其它

[Solver] UVa 11732 strcmp() 的思路

2010-01-28 18:58 169 查看
#include <stdio.h>
#include <memory.h>

int cmpTimes( char* p, char* q )
{
char* s = p;
while( *s == *q && *s ){ ++s; ++q; }
return ( s - p + 1 ) * 2 - ( (*s + *q) ? 1 : 0 );
}

char str[4000][1001];
int mat[4000][4000];		// mat[i][j]代表i串和j串的比较次数
int likeleft[4000];			// leftlike[i] 代表在i串之前最和i串相近的字符串索引

int main()
{
int i, j, k, N, l, m, n, s;
long long t;	// 存放总比较次数
for( i = 1; scanf("%d%*c", &N), N; i++ )
{
memset( &mat[0][0], 0, 4000*4000*sizeof(int) );
memset( likeleft, 0, 4000*sizeof(int) );
t = 0;
gets( str[0] );		// 读第一个串
for( j = 1; j < N; j++ )
{
gets( str[j] );
likeleft[j] = 0;		// 对于每一个新读入的串,它的likeleft初始化为0
mat[0][j] = cmpTimes( str[0], str[j] );
t += mat[0][j];	// 和第一个串比较
for( k = 1; k < j; k++ )
{
l = likeleft[k];
m = mat[l][j];		// l串 是和 k串最像的,那么就用j串和l串的关系推导出j串和k串的关系
n = mat[l][k];
if( m != n )		mat[k][j] = m < n ? m : n;		// j 串和 k串不同的位置已知
else if( m & 1 ){		// 开始的m次比较不需要,可以直接从后面不一样的开始比较
s = ( m - 1 )>>1;
mat[k][j] = m - 1 + cmpTimes( str[k] + s, str[j] + s );
}
else mat[k][j] = m;	// m==n且m%2==0, 说明 l,k,j串完全一样
mat[likeleft[j]][j] < mat[k][j] && ( likeleft[j] = k );	// 更新j串的likeleft
t += mat[k][j];		// 累加比较次数
}
}
printf("Case %d: %lld/n", i, t );
}
return 0;
}

// Uva 11732
/*
int strcmp(char *s, char *t)
{
int i;
for (i=0; s[i]==t[i]; i++) //比较1
if (s[i]=='/0')				// 比较2
return 0;
return s[i] - t[i];
}
*/
// 字符串比较次数就是<比较1>和<比较2>次数的累加。
// 给N个字符串,两两相比,问总共的比较次数。
//
// 如果直接两两算,那么时间复杂度在最坏情况下是O(l*n*n).
// 考虑到上一次的比较结果可以为下一次所用,那么问题就迎刃而解了。
// 用邻接矩阵表示比较次数,另外用一个数组存放和此串最相近的(likeleft)且位于前面的串的下标
// 那么在计算此串的时候就可以用likeleft作为参考,因为那个串是和此串最像的串。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: