ZOJ3296 —Connecting the Segments

一道很有意思的题目,活用了最长回文子串算法Manacher算法和最少区间覆盖。

最少区间覆盖:其实就是把一堆一小段区间按左边排序,区间数sum=0;然后把其中覆盖进(1,n)的区间中,开始先找其实为1的区间,找到最远的点t,找到一次,区间数sum加1,

把t赋值给tt,在把1值t,然后就不断循环找出一个区间起始点在【t+2,tt+1】的区间,找到能延伸到最远的一点tt‘,然后把tt赋值给t,然后把tt’赋值给tt,每找到一次区间数sum就加1,然后继续循环。直到tt=n位置就结束,得到最少区间数。好吧,我也感觉我说不明白= =,还是建议你百度一下吧。

Manacher算法:百度就有了。

题目传送门:http://acm.zju.edu.cn/onlinejudge/showRuns.do?contestId=1&problemCode=3296&judgeReplyIds=5

题目意思:给你一个字符串,然后让你用这个字符串处理出来的回文串,拼接成之前给出的字符串,求最少的拼接次数。

做法:先用Manacher算法处理出回文子串的区间,然后用最少区间覆盖,得出最少区间覆盖的值-1就可以得出最少拼接数。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 100050

char str1[M],str[2*M];
int rad[M],nn,n;
struct st
{
	int s,t;
}a[100010];
int cmp(const st &b,const st &c)
{
	if(b.s<c.s)
	{
		return 1;
	}
	return 0;
}
void Manacher(int *rad,char *str,int n)
{
    int i;
    int mx = 0;
    int id;
    for(i=1; i<n; i++)
    {
        if( mx > i )
			rad[i] = rad[2*id-i]<mx-i?rad[2*id-i]:mx-i;        
        else
            rad[i] = 1;
        for(; str[i+rad[i]] == str[i-rad[i]]; rad[i]++)
            ;
        if( rad[i] + i > mx )
        {
            mx = rad[i] + i;
            id = i;
        }
    }
}

int main()
{
	int i,ans,Case=1,j;
	while(scanf("%s",str1)!=EOF)
	{
		nn=strlen(str1);
		n=2*nn+2;
		str[0]='$';
		for(i=0;i<=nn;i++)
		{
			str[2*i+1]='#';
			str[2*i+2]=str1[i];
		} 
	//	printf("%s\n",str);
		Manacher(rad,str,n);
		ans=1;
		int k=0;
//处理出回文子串区间。 for(i=2;i<=n;i++) { rad[i]--; //printf("%d %d %c\n",i,rad[i],str[i]); if(rad[i]==0) continue; if(str[i]=='#') { if((rad[i])%2==1) { a[++k].s=(i-(rad[i]))/2; a[k].t=(i+(rad[i]))/2; } else { a[++k].s=(i-(rad[i])+1)/2; a[k].t=(i+(rad[i])-1)/2; } } else if(str[i]>='a'&&str[i]<='z') { if((rad[i])%2==0) { a[++k].s=(i-(rad[i]))/2; a[k].t=(i+(rad[i]))/2; } else { a[++k].s=(i-(rad[i])+1)/2; a[k].t=(i+(rad[i])-1)/2; } } } /*for(i=1;i<=k;i++) { printf("%d %d \n",a[i].s,a[i].t); }*/

//以下为最少区间覆盖。 sort(a+1,a+k+1,cmp); int end=0,sta=1,sum=1; i=1; while(i<=k&&a[i].s==sta) { if(a[i].t>end) end=a[i].t; i++; } while(end!=nn) { sta=end+1; j=end; while(i<=k&&a[i].s<=sta) { if(a[i].t>j) j=a[i].t; i++; } end=j; sum++; } printf("%d\n",sum-1); } return 0; }

 

posted on 2012-12-18 17:19  杰要加油  阅读(149)  评论(0编辑  收藏  举报

导航