zoukankan      html  css  js  c++  java
  • [HNOI2006]最短母串问题

    题目大意:给定一个字符串集,求一个最短字串,使得该集合内的串都是该串的一个子串

    算法:AC自动机+最短路+状压DP

    注意空间限制

    #include"cstdio"
    #include"cstring"
    #include"iostream"
    #include"algorithm"
    #include"bitset"
    #include"string"
    using namespace std;
    
    const int MAXN=13;
    const int MAXM=55;
    const int siz=26;
    
    int n,cnt,minn;
    string ans;
    short q[MAXN*MAXM*siz];
    int ln[MAXN*MAXM],f[MAXN][MAXN],I[MAXN][1<<12];
    string G[MAXN*MAXM],g[MAXN][MAXN],H[MAXN][1<<12];
    int rid[MAXN];
    char ch[MAXM*MAXN];
    bitset<MAXN*MAXM> vis;
    struct rpg{
    	int fail;
    	int sn[siz];
    }T[MAXN*MAXM];
    
    void ins(char *ch,int id)
    {
    	int ln=strlen(ch+1),nw=0;
    	for(int i=1;i<=ln;++i){
    		if(!T[nw].sn[ch[i]-'A']) T[nw].sn[ch[i]-'A']=++cnt;
    		nw=T[nw].sn[ch[i]-'A'];
    	}rid[id]=nw;
    	return;
    }
    
    void Getfail()
    {
    	int hd=1,tl=0;
    	for(int i=0;i<siz;++i) if(T[0].sn[i]) q[++tl]=T[0].sn[i];
    	while(hd<=tl){
    		int nw=q[hd++];
    		for(int i=0;i<siz;++i){
    			if(T[nw].sn[i]){
    				T[T[nw].sn[i]].fail=T[T[nw].fail].sn[i];
    				q[++tl]=T[nw].sn[i];
    			}else T[nw].sn[i]=T[T[nw].fail].sn[i];
    		}
    	}return;
    }
    
    void SPFA(int s)
    {
    	int hd=1,tl=1;
    	memset(ln,0x7f,sizeof(ln));
    	for(int i=1;i<=cnt;++i) G[i].clear();
    	q[hd]=s;ln[s]=0;vis[s]=1;
    	while(hd<=tl){
    		int nw=q[hd++];vis[nw]=0;
    		if(ln[T[nw].fail]>ln[nw]){
    			ln[T[nw].fail]=ln[nw];
    			G[T[nw].fail]=G[nw];
    			if(!vis[T[nw].fail]){
    				vis[T[nw].fail]=1;
    				q[++tl]=T[nw].fail;
    			}
    		}for(int i=0;i<siz;++i){
    			string str=G[nw]+(char)(i+'A');
    			if(ln[T[nw].sn[i]]<ln[nw]+1) continue;
    			if(ln[T[nw].sn[i]]>ln[nw]+1){
    				ln[T[nw].sn[i]]=ln[nw]+1;
    				G[T[nw].sn[i]]=str;
    				if(!vis[T[nw].sn[i]]){
    					vis[T[nw].sn[i]]=1;
    					q[++tl]=T[nw].sn[i];
    				}
    			}if(G[T[nw].sn[i]]<=str) continue;
    			G[T[nw].sn[i]]=str;
    			if(!vis[T[nw].sn[i]]){
    				vis[T[nw].sn[i]]=1;
    				q[++tl]=T[nw].sn[i];
    			}
    		}
    	}return;
    }
    
    void res()
    {
    	SPFA(0);
    	for(int i=1;i<=n;++i){
    		f[0][i]=ln[rid[i]];
    		g[0][i]=G[rid[i]];
    	}for(int i=1;i<=n;++i){
    		SPFA(rid[i]);
    		for(int j=1;j<=n;++j){
    			f[i][j]=ln[rid[j]];
    			g[i][j]=G[rid[j]];
    		}
    	}return;
    }
    
    void slv()
    {
    	memset(I,0x7f,sizeof(I));
    	for(int i=1;i<=n;++i) I[i][1<<i-1]=f[0][i],H[i][1<<i-1]=g[0][i];
    	for(int i=1;i<1<<n;++i){
    		for(int j=1;j<=n;++j){
    			if((i>>j-1)&1==0) continue;
    			for(int k=1;k<=n;++k){
    				if((i>>k-1)&1) continue;
    				if(I[k][i|(1<<k-1)]<I[j][i]+f[j][k]) continue;
    				if(I[k][i|(1<<k-1)]>I[j][i]+f[j][k]){
    					I[k][i|(1<<k-1)]=I[j][i]+f[j][k];
    					H[k][i|(1<<k-1)]=H[j][i]+g[j][k];
    				}else if(H[k][i|(1<<k-1)]>H[j][i]+g[j][k]){
    					H[k][i|(1<<k-1)]=H[j][i]+g[j][k];
    				}
    			}
    		}
    	}ans=H[1][(1<<n)-1],minn=I[1][(1<<n)-1];
    	for(int i=2;i<=n;++i){
    		if(minn>I[i][(1<<n)-1]){
    			minn=I[i][(1<<n)-1];
    			ans=H[i][(1<<n)-1];
    		}else if(minn==I[i][(1<<n)-1]&&ans>H[i][(1<<n)-1]){
    			ans=H[i][(1<<n)-1];
    		}
    	}return;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i) scanf("%s",ch+1),ins(ch,i);
    	Getfail();res();slv();
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    [转]VC++下使用ADO操作数据库
    VC++ GetSafeHwnd()和GetSafeHandle()
    VC++ GetSafeHwnd用法
    C++中的const成员函数(函数声明后加const,或称常量成员函数)用法详解
    VC++ Debug条件断点使用
    VC++为你的程序增加内存泄露检测
    VC++ Debug格式化数值显示
    VC++Debug查看堆对象内容,即使符号已经超出作用范围
    VC++ Debug产生异常时中断程序执行Break on Exception
    一个简单的伪随机数发生算法
  • 原文地址:https://www.cnblogs.com/AH2002/p/10019683.html
Copyright © 2011-2022 走看看