2. LZW网页判重 (20分)

2. LZW网页判重 (20分)

问题背景

有一种简单的网页判重的方法,通过求两个网页内容的最长公共子序列(LCS)长度来判定两个网页的相似程度。如:
(网页A)老师:请用“果然”造句。
(网页B)学生:先吃水后喝汽水……
它们的最长公共子序列为“果然”,长度为2。注意这里的“子序列”并不要求连续。

类似的,下面两个网页:
(网页A)老师:请用“果然”造句。
(网页B)学生:先吃水果,然后喝汽水,果然拉肚子……

最长公共子序列还是“果然”,长度为2。但不难看出,由于“果然”两个字在网页B中也曾连续出现,第二组网页比第一组更加“相似”。为了区分开这两种情况的区分度,我们改用一种称为LZW的理论。为了严格的叙述相似度的计算方法,我们首先定义“文本单元”。

假定网页用一个不包含空白字符(空格、回车换行、水平制表符)的字符串来表示。它只包含纯文本,没有标签。在计算相似度之前,你应该首先对该字符串进行处理,划分成一个个“文本单元”。每个文本单位可以是一个中文字、英文单词(由一个或多个连续的半角英文字母和数字组成,正规表达式为[a-zA-Z0-9]+)、或者一个标点符号。

根据上述定义,同一个标点符号的全角和半角应该被作为不同的文本单元,尽管他们看起来可能很相近;每个单独全角英文和全角数字都应该被看成一个单独的文本单元,而连续的半角英文字母和数字应被看成一个整体。总之,全角的字符可以与中文字同等对待。

这样,网页被看成文本单元序列。例如,网页“内容?123456??web2.00#”切分出的文本单元序列为(为了显示方便,用下划线分隔各文本单元):
__?_1_2_345_6_?_?_web2_._00_#

而网页“why内容相似??1234567890,web#00”的切分结果为:
why___相_似_?_?_1234567890_,_web_#_00

黑体部分给出了两个网页的一个公共子序列。注意“内容”、“??”分别在两个网页中都是连续出现的文本单元。为了奖励这种情况,LZW规定一段由连续k个文本单元组成的字符串权值为k2。在刚才的例子中,“内容”、“??”的权值均为4。但“00”是一个数字串,应当被看成一个单独的文本单元。所以权值仅为1。

根据上述规则,公共子序列“内容 ?? 00”的权值为22+22+1=9。在所有可能的子序列中,这个权值是最大的。

给定两个网页,求他们的LZW相似度,即所有可能的公共子序列中的最大权值。

注意

1) 输入的网页内容以GBK编码(参见FAQ)
2) 除了大小写英文字母和数字之外的其他半角字符均视为标点符号。

输入格式

包含两行,分别是网页A和B对应的字符串(不包含空白字符)。每行至少包含5个字节,最多包含200个字节。

输出格式

输出仅一行,包含一个整数,为两个网页的LZW相似度。

样例输入

内容?123456??web2.00#
why内容相似??1234567890,web#00

样例输出

9

样例解释

尽管两个网页里看上去都有“123456”但一方面第一个网页中混杂的全角和半角字符,而另一方面,即使全部改成半角字符,由于数字串“123456”和“1234567890”将分别看成一个单独的文本单元,因此无法部分匹配。

 

 

全角和半角不知道怎么编程区分,想了很长时间。以前编的程序,没遇到这个问题,哎。

我不懂怎么编,是别人的代码:

 

#include "iostream"
using namespace std;

struct mystr
{
    char *s;
    struct mystr * next;    
    mystr(){s=NULL; next=NULL;}
};
bool getstr(char *s, int n);
void split(char *,mystr &);
int getweight(mystr &substr1,mystr &substr2);
void strcpy(char *s,char *d, int start,int len)
{
     int i;
     for(i=0;i<len;i++ ) d[i]=s[start+i];
     d[i]=0;
}
int main()
{
    char s1[201],s2[201];
    getstr(s1,200);
    getstr(s2,200);
    mystr substr1,substr2;
    split(s1,substr1);
    split(s2,substr2);
    int weight= getweight(substr1,substr2);
    cout<<weight;
   return 0;
}

bool getstr(char *s, int n)
{
    char ch;
    int i;
    for(i=0; (ch=getchar())!='/n'&&i<n;i++) s[i]=ch;
    s[i]=0;
    return true;  
}
void split(char *s,mystr &substr)//字符分为三类,全角(符号和汉字),半角数字和字母,半角标点
{
    mystr *p=&substr;
    int i,j;
    i=0,j=0;
    while(s[i])
      {
        while(s[i]==' ') i++;//过滤空格
        if (!s[i]) break;
       p->next=new mystr;
        p=p->next;
       if (s[i]&128)//全角字符,包括汉字
        {
            p->s=new char[3];
            strcpy(s,p->s,i,2);
            i+=2;
            j=i;
            // continue;
        }
       else //if(s[i]>='0'&&s[i]<='9'||s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z')
          {
             j=i;
             while(s[j]>='0'&&s[j]<='9'||s[j]>='a'&&s[j]<='z'||s[j]>='A'&&s[j]<='Z') j++;
             if (j!=i)
               {
                p->s=new char[j-i+1];
                strcpy(s,p->s,i,j-i);
                i=j;     
               }
            else
             {
              p->s=new char[2];
              strcpy(s,p->s,i,1);
              i++;  
             }
         
          }
      }
}


int getweight(mystr &substr1,mystr &substr2)
{
    mystr *p1=substr1.next;
    mystr *p2=substr2.next;
    mystr *pto1,*pto2;
    int weight=0,count=0;
    while(p1)
      {
       while(p2)
       {
        pto1=p1,pto2=p2;
        count=0;
        while(!strcmp(pto1->s,pto2->s))
        {
         count++;
         pto1=pto1->next;
         pto2=pto2->next;
        }
        weight+=count*count;
        if (pto2!=p2)     p2=pto2;    
        else p2=p2->next;
       }
       p1=p1->next;
      }   
    return weight;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值