poj3080-kmp+列舉子串 求最長公共子串

zzc2227372發表於2014-07-14

因為一直有事這道題又有點繁瑣, 所以寫了好多天今天才AC,不過1A還是很爽的。

思路還是很簡單的,對第一個主串列舉其所有子串,然後將每個子串都與其他的所以主串KMP匹配,如果是所有主串的公共子串則記錄 並選出最大的一個  注意這道題要字典序最小

 

程式碼:

#include "iostream"
using namespace std;
#define  maxsize   80
char c[11][maxsize];
char substring[maxsize];
int next[11][maxsize];
char cans[maxsize];

void getnext(int  n,int length)
{
	
	int  i=0,j=-1;
	next[n][0]=-1;
	while(i<length)
	{
		if (j==-1||c[n][i]==c[n][j])
		{
			i++;
			j++;
			next[n][i]=j;
		}
		else
		{
			j=next[n][j];
		}
	}
}

int	KMP(int  n,int length)
{

	int i=0,j=0;
	int length1=strlen(substring);
	while (i<length&&j<length1)
	{
		if (j==-1||c[n][i]==substring[j])
		{
			i++;
			j++;
		}
		else
		{
			
			j=next[n][j];
		}
	}
	
	if (j>=length1)
	{
		return i-length1 ;
	}
	else
		return -3;
	
	
}
int main()
{
	int case1;
	scanf("%d",&case1);
	while (case1--)
	{
		int  num;
		scanf("%d",&num);
		int i,j;
		for(i=0;i<num;i++)
		{
			scanf("%s",c[i]);	
			int length=strlen(c[i]);
			getnext(i,length);//計算每個字串的next
		}
		int length1=strlen(c[0]);
		int tans=0;
	
		//列舉從c[0]所有子串
		for (i=2;i<length1;i++)//i表示子串長度
		{
			for (j=0;j<length1;j++)//j   表示子串第一個元素位置
			{
				substring[0]='\0';
				strncpy(substring,c[0]+j,i+1);//得到一個子串
				int flag=1;
				int slen=strlen(substring);
				//判斷子串在不在目標串中
				for (int k=1;k<num;k++)
				{
					int temp=KMP(k,strlen(c[k]));
					
					
					if (temp==-3)//說明這個子串不存在於c[k]
					{
						flag=0;
						break;
					}
				}
				if (flag==1)
				{
					if (tans==slen)
					{
						if (strcmp(cans,substring)>0)
						{
						tans=slen;

						strcpy(cans,substring);	
						}
					}
					if (tans<slen)
					{
						tans=slen;
						strcpy(cans,substring);	
					}
					
				}
			}
		}
		
		if (tans<3)
		{
			cout<<"no significant commonalities"<<endl;
		}
		else
			cout<<cans<<endl;
		
	}
	
}

 

相關文章