HDU-2296 Ring(AC自动机+DP)

题目大意:给出的m个字符串都有一个权值。用小写字母构造一个长度不超过n的字符串S,如果S包含子串s,则S获取s的权值。输出具有最大权值的最小字符串S。

题目分析:先建立AC自动机。定义状态dp(step,u)表示长度为step、在u节点上的最大权值。状态转移方程为:dp(step,u)=max(dp(step-1,v)+w(u))。其中,v为能到达u的前一个节点。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<string>
# include<cstring>
# include<algorithm>
using namespace std;

int cnt;
int ch[1200][26];
int fail[1200];
int val[1200];
int w[105];

void init()
{
	cnt=0;
	memset(ch,-1,sizeof(ch));
	memset(val,0,sizeof(val));
}

int idx(char c)
{
	return c-'a';
}

void insert(char *s,int key)
{
	int len=strlen(s);
	int r=0;
	for(int i=0;i<len;++i){
		int c=idx(s[i]);
		if(ch[r][c]==-1) ch[r][c]=++cnt;
		r=ch[r][c];
	}
	val[r]=w[key];
}

void getFail()
{
	queue<int>q;
	fail[0]=0;
	for(int i=0;i<26;++i){
		if(ch[0][i]==-1)
			ch[0][i]=0;
		else{
			fail[ch[0][i]]=0;
			q.push(ch[0][i]);
		}
	}
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;++i){
			if(ch[u][i]==-1)
				ch[u][i]=ch[fail[u]][i];
			else{
				fail[ch[u][i]]=ch[fail[u]][i];
				q.push(ch[u][i]);
			}
		}
	}
}

char h[105][15];
int dp[55][1200];
string path[55][1200];

bool isSmall(string s,string t)
{
	if(t=="") return true;
	if(s.size()<t.size()) return true;
	if(s.size()>t.size()) return false;
	return s<t;
}

string DP(int n)
{
	memset(dp,-1,sizeof(dp));
	dp[0][0]=0;
	for(int i=0;i<=n;++i) for(int j=0;j<=cnt;++j)
		path[i][j]="";
	int fen=0;
	for(int i=0;i<=n;++i){
		for(int j=0;j<=cnt;++j){
			if(dp[i][j]==-1) continue;
			for(int c=0;c<26;++c){
				if(dp[i+1][ch[j][c]]<dp[i][j]+val[ch[j][c]]){
					dp[i+1][ch[j][c]]=dp[i][j]+val[ch[j][c]];
					path[i+1][ch[j][c]]=path[i][j]+(char)('a'+c);
				}else if(dp[i+1][ch[j][c]]==dp[i][j]+val[ch[j][c]]){
					if(isSmall(path[i][j]+(char)('a'+c),path[i+1][ch[j][c]]))
						path[i+1][ch[j][c]]=path[i][j]+(char)('a'+c);
				}
			}
			if(i>0) fen=max(fen,dp[i][j]);
		}
	}
	if(fen==0) return "";
	string res="";
	for(int i=1;i<=n;++i) for(int j=0;j<=cnt;++j){
		if(dp[i][j]==fen&&isSmall(path[i][j],res)){
			res=path[i][j];
		}
	}
	return res;
}

int main()
{
	int T,n,m;
	scanf("%d",&T);
	while(T--)
	{
		init();
		scanf("%d%d",&n,&m);
		for(int i=0;i<m;++i)
			scanf("%s",h[i]);
		w[0]=0;
		for(int i=1;i<=m;++i)
			scanf("%d",w+i);
		for(int i=0;i<m;++i)
			insert(h[i],i+1);
		getFail();
		cout<<DP(n)<<endl;
	}
	return 0;
}

 

posted @ 2016-10-26 19:32  20143605  阅读(236)  评论(0编辑  收藏  举报