编程之美: 第三章 结构之法 3.5最短摘要的生成

来源:互联网 发布:淘宝刀剑神域99 编辑:程序博客网 时间:2024/05/01 12:01
/*最短摘要的生成;输入一些关键词之后,搜索引擎会返回许多结果,每个结果都包含一段概括网页内容的还要。标题和URL之间的内容就是我们所说的摘要假设给定的已经是网页分词之后的结果,词语序列数组为W。其中W[0],W[1],...,W[N]为一些已经分好的词语。假设用户输入的搜索关键词为数组Q,其中Q[0],Q[1],...,Q[m]为所有输入的搜索关键词。这样,生成的最短摘要实际上就是一串相互联系的分词序列。比如从W[i]到W[j],其中,0<i<j<=N。例如图中:“微软亚洲研究院成立于1998年,我们的使命”包含了所有的关键字 --- “微软亚洲研究院 使命”分析:“微软/亚洲/研究院。。。”,这就是我们期望的W数组序列。w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q11从W数组的第一个位置开始查找出一段包含所有关键词数组的Q的序列。计算当前的最短长度,并更新Seq数组。2对目标数组W进行遍历,从第二个位置开始,重新查找包含所有关键词数组Q的序列,同样计算出其最短长度,以及更新包含所有关键词的序列Seq,然后求出最短距离3依次操作下去,一直到遍历至目标数组W的最后一个位置为止。要遍历所有其他的关键词(M),对于每个关键词,要遍历整个网页的词(N),而每个关键词在整个网页中的每一次出现,要遍历所有的Seq,以更新这个关键词与所有其他关键词的最小距离。时间复杂度O(N^2*M)解法2:进行查找的时候,总是重复地循环,效率不高。问题在于入股一次把所有的关键词都扫面到,而且不遗漏。如何把两次扫面的结果联系起来?第一次扫描的时候,假设需要包含所有的关键词,将得到如下结果:w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1#                       #那么下次搜啊秒应该怎么办?显然,可以把第一个被扫描的位置挪动q0处。如果把第一个被扫描的位置继续往后面移动一格,这样包含的序列中将减少了关键词q0.w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1            #           #那么,如果我们把第二个扫面位置往后移,这样就可以找到下一个包含所有关键词的序列:如下w0,w1,w2,w3,q0,w4,w5,q1,w6,w7,w8,q0,w9,q1               #                    #这样问题就和第一次扫描碰到的情况一样了。依次扫描下去,在w中找出所有包含q的序列,并且找出其中的最小值,就可以得到最终结果输入:马超,字孟起,扶风茂陵人,生于三国末年。马超一生,勇冠三军,三国中家喻户晓的名将。(网页内容)2(表示关键词的个数)马超 三国输出:born in FufengMaoling输入:MaChao called mengqi lived in SanGuo. All of MaChao life, always win, famous in SanGuo.2MaChao SanGuo.输出:SanGuo. All of MaChao*//*关键:1 //最短摘要的主要算法:如果没有找到包含所有关键词的摘要,那么向后移动指针;一旦找到,那么判断当前找到的这段摘要长度是否小于已经记录的最短长度;若小于//那么就更新最短长度,并且设定最终返回的摘要的起止指针。然后继续向后移动起始指针,通过这个方法,来缩短距离。2 while(!isConcluded(strPage,iBeg,iEnd,strKeyWord,iWordNum) && iEnd < iLen)//如果没有包含所有关键词,就向后移动结束指针{iEnd++;}3 while(isConcluded(strPage,iBeg,iEnd,strKeyWord,iWordNum))// 如果包含了,那么进行更新操作{if(iEnd - iBeg < iPageLen)//如果当前全部包含关键词摘要的长度比最短长度要小,就更新{iPageLen = iEnd - iBeg;iAbsBeg = iBeg;iAbsEnd = iEnd;}iBeg++;//最精彩的一步,将起点指针不断后移,来使包含全部关键字摘要的长度减少*/#include <stdio.h>#include <string.h>#include <iostream>using namespace std;const int MAXSIZE = 100;const int INF = 0x7fffffff;//判断如何包含,所采用的方法是用strstr函数来判断bool isConcluded(char* strPage,int iBeg,int iEnd,char strKeyWord[][MAXSIZE],int iWordNum){if(!strPage || !strKeyWord || iBeg < 0 || iEnd < 0 || iBeg > iEnd || iWordNum <= 0){return false;}char strNewPage[MAXSIZE];//生成一个新的字符串for(int i = iBeg ; i <= iEnd ; i++){strNewPage[i-iBeg] = strPage[i];}strNewPage[iEnd+1] = '\n';for(int i = 0 ; i < iWordNum ; i++){if(!strstr(strNewPage,strKeyWord[i])){return false;}}return true;}//最短摘要的主要算法:如果没有找到包含所有关键词的摘要,那么向后移动指针;一旦找到,那么判断当前找到的这段摘要长度是否小于已经记录的最短长度;若小于//那么就更新最短长度,并且设定最终返回的摘要的起止指针。然后继续向后移动起始指针,通过这个方法,来缩短距离。pair<int,int> shortestAbstract(char* strPage,int iLen,char strKeyWord[][MAXSIZE],int iWordNum){int iPageLen = INF;int iBeg = 0,iEnd = 0;int iAbsBeg = 0,iAbsEnd = 0;while(true){while(!isConcluded(strPage,iBeg,iEnd,strKeyWord,iWordNum) && iEnd < iLen)//如果没有包含所有关键词,就向后移动结束指针{iEnd++;}while(isConcluded(strPage,iBeg,iEnd,strKeyWord,iWordNum))// 如果包含了,那么进行更新操作{if(iEnd - iBeg < iPageLen)//如果当前全部包含关键词摘要的长度比最短长度要小,就更新{iPageLen = iEnd - iBeg;iAbsBeg = iBeg;iAbsEnd = iEnd;}iBeg++;//最精彩的一步,将起点指针不断后移,来使包含全部关键字摘要的长度减少}if(iEnd >= iLen)//判断字符串越界{break;}}return make_pair<int,int>(iAbsBeg,iAbsEnd);}void printAbstract(char* strPage,int iBeg,int iEnd){for(int i = iBeg ; i <= iEnd ; i++){printf("%c",strPage[i]);}printf("\n");}void process(){int n;char strPage[MAXSIZE*MAXSIZE];//被查找网页应该用一个大字符串即可,但是用户输入的关键词,必须要用二维字符指针来保存char strKeyWord[MAXSIZE][MAXSIZE];while(NULL != gets(strPage)){scanf("%d",&n);for(int i = 0 ; i < n ; i++){scanf("%s",strKeyWord[i]);}pair<int,int> pairRes = shortestAbstract(strPage,strlen(strPage),strKeyWord,n);printAbstract(strPage,pairRes.first,pairRes.second);}}int main(int argc,char* argv[]){process();getchar();return 0;}

0 0
原创粉丝点击