UVa---11732...超时...TLE...高分求好算法....

sciencesuneast 2010-01-25 02:37:26
其实题目说的很简单...
就是返回对两个字符串比较次数....

只是数据量有点大...
不处理好算法就会超时...

我实在不知道还有什么好的方法...

特地来向大家求助....

原题地址....
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=117&problem=2832&mosmsg=Submission+received+with+ID+7709541

这个是google翻译的结果...

http://translate.google.cn/translate?hl=zh-CN&sl=en&u=http://uva.onlinejudge.org/index.php%3Foption%3Dcom_onlinejudge%26Itemid%3D8%26category%3D117%26page%3Dshow_problem%26problem%3D2832&ei=P49cS_6FGY_m7AP4xJUT&sa=X&oi=translate&ct=result&resnum=1&ved=0CAkQ7gEwAA&prev=/search%3Fq%3D11732%2B-%2Bstrcmp()%2BAnyone%253F%26hl%3Dzh-CN%26client%3Dfirefox-a%26rls%3Dorg.mozilla:zh-CN:official%26hs%3DUGS%26newwindow%3D1


然后贴上我的TLE代码...



#include<iostream>

using namespace std;

char str[4005][1008];
long long ans;
int n,len[4005];

void str_cmp(int a,int b)
{
int i,l;
if(len[a]!=len[b])
l=len[a]<len[b]?len[a]:len[b],ans++;
else
l=len[a],ans+=2;
for(i=0;i<l;i++)
if(str[a][i]==str[b][i])
ans+=2;
else
return ;
}

int main()
{
// freopen("in.txt","r",stdin);
int i,j,cas=1;
char buf;
while(scanf("%d%c",&n,&buf)&&n)
{
gets(str[0]);
len[0]=strlen(str[0]);
ans=0;
for(i=1;i<n;i++)
{
gets(str[i]);
len[i]=strlen(str[i]);
for(j=i-1;j>=0;j--)
str_cmp(i,j);
}
cout<<"Case "<<cas++<<": "<<ans<<endl;

}

return 0;
}




如果大家有什么好的想法欢迎提出....

谢谢.......
...全文
182 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
sciencesuneast 2010-03-04
  • 打赏
  • 举报
回复


额,我自己后俩AC了...
竟然把这个帖子给忘了...

谢谢大家的回复....
pang123hui 2010-01-29
  • 打赏
  • 举报
回复
up
绿色夹克衫 2010-01-28
  • 打赏
  • 举报
回复
用trie也可以,排个序再处理也行,跟trie一个思路。排序后可以批量算,
比如A开头同不是A开头的用乘法可以直接算出2批的结果。同为A开头的再递归到下一位如法炮制就行。
复杂度最高的就在排序部分。
  • 打赏
  • 举报
回复
这个网站只能看自己的统计数据吗?怎么看其他人的时间?
  • 打赏
  • 举报
回复
0.924s.
没仔细看输出要用64bit的longlong,结果wa了一次。


#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];
int likeleft[4000];

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;
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];
n = mat[l][k];
if( m != n ) mat[k][j] = m < n ? m : n;
else if( m & 1 ){
s = ( m - 1 )>>1;
mat[k][j] = m - 1 + cmpTimes( str[k] + s, str[j] + s );
}
else mat[k][j] = m;
mat[likeleft[j]][j] < mat[k][j] && ( likeleft[j] = k );
t += mat[k][j];
}
}
printf("Case %d: %lld\n", i, t );
}
return 0;
}
IT_lau 2010-01-28
  • 打赏
  • 举报
回复
帮顶,等牛人解答
FancyMouse 2010-01-28
  • 打赏
  • 举报
回复
今天训练刚刚做到,Trie切掉。建立一个Trie树,然后遍历这个Trie树就可以得到答案。有一些比较麻烦的细节需要仔细想但可做。用Trie的话线性。

lz的朴素做法O(ln^2)肯定挂。偶一开始写的62叉树,没有用左孩子右兄弟表示,结果每个节点memset初始化也让偶tle了……本来复杂度只是O(ln)的也能挂。最后迫不得已写了左孩子右兄弟才勉强过的(1.9s。时限是2s)

至于上面放代码的,自己拿下面的数据测:第一行4000,然后4000行每行长1000的全0字符串。2秒钟里跑不完的oj上肯定tle。

----
>正确做法是构造一个邻接矩阵,存放两个字符串之间的Aij。

新的字符串Sk加入后,先和第一个字符串S0比较,得到A0k。接着它和S1比较的次数就可以通过A01来简化。

if(A0k != A01) A1k = min(A0k, A01)
else 从A0k个字符处开始比较Sk和S1

大致就是这样,动态规划。
----
这个做法第一没法称为动态规划,第二依然会超时。考虑这个数据:
aaaaaaaaaaa
bbbbbbbbbbb
aaaaaaaaaaa
bbbbbbbbbbb
。。。
按照偶的理解,乃这做法对于这个数据依然会退化到O(ln^2)
logiciel 2010-01-27
  • 打赏
  • 举报
回复
9楼的C程序效率不够,现改为C++,用list操作.
#include <iostream>
#include <list>
#include <numeric>
#include <algorithm>
using namespace std;

#define MAX_CHAR_ID ('z' - '0' + 1)
#define MAX_STR_POS 1000
#define MAX_STR_ID 4000

typedef list<int> STR_ID_LIST;

STR_ID_LIST str_id_list[MAX_CHAR_ID][MAX_STR_POS];
STR_ID_LIST same_str_id_list; //与当前输入的字符串相同的已输入字符串的编号
int str_len[MAX_STR_ID];
char str[MAX_STR_POS + 1];
long ans;
int n;
int max_len;


/*检查第1个字符*/
void check_first_char(int char_id, int str_id)
{
STR_ID_LIST::iterator i;

for (i = str_id_list[char_id][0].begin(); i != str_id_list[char_id][0].end(); ++i)
{
same_str_id_list.push_back(*i);
}
ans += (same_str_id_list.size() + str_id);
}

/*检查其他字符*/
void check_rest_chars(int char_id, int str_pos, int str_id)
{
STR_ID_LIST::iterator i = same_str_id_list.begin();
STR_ID_LIST::iterator j;

while (i != same_str_id_list.end())
{
j = i++;
if (binary_search(str_id_list[char_id][str_pos].begin(),
str_id_list[char_id][str_pos].end(),
*j))
{
ans += 2;
}
else
{
if (str_len[*j] >= str_len[str_id])
{
ans++;
}
same_str_id_list.erase(j);
}
}
}

/*重置reset_str_id_list*/
void reset_str_id_list (void)
{
int i, j;
for (i = 0; i < MAX_CHAR_ID; i++)
{
for (j = 0; j < max_len; j++)
{
str_id_list[i][j].clear();
}
}
same_str_id_list.clear();
}

int main()
{
int i, j, cas=1;
char dummy;
freopen("a.txt","r",stdin);
while(scanf("%d%c",&n,&dummy)&&n)
{
ans = max_len = 0;
for (i = 0; i < n; i++)
{
char c;
int len;
gets(str);
str_len[i] = len = strlen(str);
if (max_len < len)
{
max_len = len;
}
for (j = 0; c = str[j]; j++)
{
/*把字符转换为str_id_list的第1个下标*/
int char_id = c- '0';
if (i > 0)
{
if (j == 0)
{
check_first_char(char_id, i);
}
else if (same_str_id_list.size() > 0)
{
check_rest_chars(char_id, j, i);
}
}
str_id_list[char_id][j].push_back(i);/*把当前输入字符串的编号存入str_id_list*/
}
}
cout << "Case " << cas++ << ans << endl;
reset_str_id_list();
}

return 0;
}
小小攻城师 2010-01-27
  • 打赏
  • 举报
回复
楼主的代码测试完全不对啊。
题目意思楼主没明白?问比较次数。
第一组数据 a b的测试次数为1因为只在for的条件比较一次,不同,退出,所以只比较一次而已,楼主让每次比较都加2肯定错误了。
楼上的代码我测试数据都是正确的
  • 打赏
  • 举报
回复
题目最后都提示你了,如果挨个比较,最坏情况是1000*N^2,必然tle。

正确做法是构造一个邻接矩阵,存放两个字符串之间的Aij。

新的字符串Sk加入后,先和第一个字符串S0比较,得到A0k。接着它和S1比较的次数就可以通过A01来简化。

if(A0k != A01) A1k = min(A0k, A01)
else 从A0k个字符处开始比较Sk和S1

大致就是这样,动态规划。
StephenGaoYu 2010-01-26
  • 打赏
  • 举报
回复
友情帮顶
logiciel 2010-01-26
  • 打赏
  • 举报
回复
以下修改还可节省一些运行时间:

#define MAX_CHAR_ID ('z' - '0' + 1)
//int char_id = convert_char_index(c);
int char_id = c - '0';
logiciel 2010-01-26
  • 打赏
  • 举报
回复
LZ程序运行样例不能得到期望输出,所以我怀疑ans+=2是否对.但7楼的简化也不对,而且不能解决根本问题.

以下是新考虑的算法,减少了逐个比较的次数,但增加了链表操作,不知是否能AC.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_CHAR_ID 62
#define MAX_STR_POS 1000
#define MAX_STR_ID 4000

typedef struct _str_id_type
{
int id; //输入字符串的编号
struct _str_id_type *next;
} str_id_type;

str_id_type str_id_buff[MAX_CHAR_ID][MAX_STR_POS];
int same_str_id_buff[MAX_STR_ID]; //与当前输入的字符串相同的已输入字符串的编号
int same_str_id_count;
int str_len[MAX_STR_ID];
char str[MAX_STR_POS + 1];
long ans;
int n;
int max_len;

/*把字符转换为str_id_buff的第1个下标*/
int convert_char_index (char c)
{
int char_index;
if (c >='0' && c <= '9')
{
char_index = c - '0';
}
else if (c >='A' && c <= 'Z')
{
char_index = c - 'A' + 10;
}
else
{
char_index = c - 'a' + 36;
}
return char_index;
}

/*把当前输入字符串的编号存入str_id_buff*/
void put_str_id (int char_id, int str_pos, int str_id)
{
str_id_type *p = &str_id_buff[char_id][str_pos];
str_id_type *q = (str_id_type *)malloc(sizeof(str_id_type));
q->id = str_id;
q->next = p->next;
p->next = q;
}

/*检查第1个字符*/
void check_first_char(int char_id, int str_id)
{
str_id_type *p = str_id_buff[char_id][0].next;
same_str_id_count = 0;
while (p)
{
same_str_id_buff[same_str_id_count++] = p->id;
p = p->next;
}
ans += (same_str_id_count + str_id);
}

/*检查其他字符*/
void check_rest_chars(int char_id, int str_pos, int str_id)
{
int i = 0;

while (i < same_str_id_count)
{
int same_str_id = same_str_id_buff[i];
int found = 0;
str_id_type *p = str_id_buff[char_id][str_pos].next;
while (p)
{
if (same_str_id == p->id)
{
/*当前输入的字符串与以前输入的字符串的第str_pos个字符相同*/
found = 1;
break;
}
p = p->next;
}
if (found)
{
ans += 2;
i++;
}
else
{
if (str_len[same_str_id] >= str_len[str_id])
{
ans++;
}
/*把最后一个移到当前位置*/
same_str_id_buff[i] = same_str_id_buff[--same_str_id_count];
}
}
}

/*重置reset_str_id_buff*/
void reset_str_id_buff (void)
{
int i, j;
for (i = 0; i < MAX_CHAR_ID; i++)
{
for (j = 0; j < max_len; j++)
{
str_id_type *p = str_id_buff[i][j].next;
if (p)
{
str_id_type *q;
while (p)
{
q = p;
p = p->next;
free(q);
}
str_id_buff[i][j].next = NULL;
}
}
}
}

int main()
{
int i, j, cas=1;
char dummy;
freopen("a.txt","r",stdin);
while(scanf("%d%c",&n,&dummy)&&n)
{
ans = max_len = 0;
for (i = 0; i < n; i++)
{
char c;
int len;
gets(str);
str_len[i] = len = strlen(str);
if (max_len < len)
{
max_len = len;
}
for (j = 0; c = str[j]; j++)
{
int char_id = convert_char_index(c);
if (i > 0)
{
if (j == 0)
{
check_first_char(char_id, i);
}
else if (same_str_id_count > 0)
{
check_rest_chars(char_id, j, i);
}
}
put_str_id(char_id, j, i);
}
}
printf("Case %d: %d\n", cas++, ans);
reset_str_id_buff();
}

return 0;
}
sciencesuneast 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 wangchentangjuan 的回复:]
不能打开其他的链接 友情UP
[/Quote]

打不开还是什么...?

有人贴出题目了...

麻烦你帮我看看哈...

我实在是没辙了....
problc 2010-01-25
  • 打赏
  • 举报
回复
up,贴一下题吧
J
“strcmp()” Anyone?

Input: Standard Input

Output: Standard Output




strcmp() is a library function in C/C++ which compares two strings. It takes two strings as input parameter and decides which one is lexicographically larger or smaller: If the first string is greater then it returns a positive value, if the second string is greater it returns a negative value and if two strings are equal it returns a zero. The code that is used to compare two strings in C/C++ library is shown below:

int strcmp(char *s, char *t)
{
int i;
for (i=0; s[i]==t[i]; i++)
if (s[i]=='\0')
return 0;
return s[i] - t[i];
}

Figure: The standard strcmp() code provided for this problem.




The number of comparisons required to compare two strings in strcmp() function is never returned by the function. But for this problem you will have to do just that at a larger scale. strcmp() function continues to compare characters in the same position of the two strings until two different characters are found or both strings come to an end. Of course it assumes that last character of a string is a null (‘\0’) character. For example the table below shows what happens when “than” and “that”; “therE” and “the” are compared using strcmp() function. To understand how 7 comparisons are needed in both cases please consult the code block given above.



t
h
a
N
\0

t
h
e
r
E
\0


=
=
=


=
=
=




t
h
a
T
\0
t
h
e
\0



Returns negative value

7 Comparisons
Returns positive value

7 Comparisons




Input

The input file contains maximum 10 sets of inputs. The description of each set is given below:



Each set starts with an integer N (0<N<4001) which denotes the total number of strings. Each of the next N lines contains one string. Strings contain only alphanumerals (‘0’… ‘9’, ‘A’… ‘Z’, ‘a’… ‘z’) have a maximum length of 1000, and a minimum length of 1.



Input is terminated by a line containing a single zero. Input file size is around 23 MB.



Output
For each set of input produce one line of output. This line contains the serial of output followed by an integer T. This T denotes the total number of comparisons that are required in the strcmp() function if all the strings are compared with one another exactly once. So for N strings the function strcmp() will be called exactly times. You have to calculate total number of comparisons inside the strcmp() function in those calls. You can assume that the value of T will fit safely in a 64-bit signed integer. Please note that the most straightforward solution (Worst Case Complexity O(N2 *1000)) will time out for this problem.



Sample Input Output for Sample Input
2

a

b

4

cat

hat

mat

sir

0
Case 1: 1

Case 2: 6





--------------------------------------------------------------------------------

Problem Setter: Shahriar Manzoor, Special Thanks: Md. Arifuzzaman Arif, Sohel Hafiz, Manzurur Rahman Khan

beyond071 2010-01-25
  • 打赏
  • 举报
回复
访问原题地址超时
cocat 2010-01-25
  • 打赏
  • 举报
回复
帮顶
z569362161 2010-01-25
  • 打赏
  • 举报
回复
帮你顶
wangchentangjuan 2010-01-25
  • 打赏
  • 举报
回复
不能打开其他的链接 友情UP
sciencesuneast 2010-01-25
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 logiciel 的回复:]
“ans+=2”应是“ans++”吧。

以下把str_cmp简化了一些,请试一试:

C/C++ codevoid str_cmp(int a,int b)
{int i,l;char*p=str[a];char*q=str[b];
l=len[a]<=len[b]?len[a]:len[b];
ans++;for(i=0;i<l;i++,p++,q++)if(*p==*q)
ans++;elsereturn ;
}
[/Quote]

是ans+=2....

codevoid str_cmp(int a,int b)
{int i,l;char*p=str[a];char*q=str[b];
l=len[a]<=len[b]?len[a]:len[b];
ans++;for(i=0;i<l;i++,p++,q++)if(*p==*q)
ans++;elsereturn ;
}


里面有两次比较操作...

这题是UVa的11732....

还是要谢谢咯...
加载更多回复(1)

64,641

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧