• 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;
    }
    
  • 相关阅读:
    给脚本绑定LUA解释器
    Flash Socket连接受限解决方法
    使用CMake构建编译环境
    如何使用OpenCL编写程序
    使用zzip和minizip解压缩文件
    使用CURL库下载文件
    使用GDI+保存位图文件为PNG文件
    linux学习
    Tomcat6连接池配置
    ArrayList与LinkedList性能差别
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/6001604.html
Copyright © 2020-2023  润新知