zoukankan      html  css  js  c++  java
  • bzoj 1195: [HNOI2006]最短母串【状压dp】

    我有病吧……明明直接枚举是否匹配就可以非要写hash,然后果然冲突了(……我个非酋居然还敢用hash
    设f[s][i]为已选串状态为s并且最后一个串是i,还有预处理出g[i][j]表示最长有长为g[i][j]的i串后缀等于j串前缀这里,直接暴力匹配即可……
    然后注意到比较麻烦的事要求字典序最小,但是因为空间限制我们又不能给每个f存一个串,所以我们设t[s][i][j]为状态使f[s][i]长度最小且字典序最小的选串顺序的第j个选的是那个串,这个更新f[s][i]的时候直接更新,注意如果有等于当前f[s][i]的情况,要分别把旧的t[s][i]和当前情况对应的两个串都求出来比一下字典序
    长度dp部分随便转移一下就好

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=15;
    int n,f[5005][N],t[5005][N][N],g[N][N],len[N],ans=1e9,b[N];
    bool v[N];
    char c[N][55],s1[1005],s2[1005],a[1005];
    struct qwe
    {
    	int l;
    	char c[55];
    };
    bool cmp(const qwe &a,const qwe &b)
    {
    	for(int i=1;i<=min(a.l,b.l);i++)
    		if(a.c[i]!=b.c[i])
    			return a.c[i]<b.c[i];
    	return a.l<b.l;
    }
    bool ok(int i,int j,int l)
    {
    	for(int k=1;k<=l;k++)
    		if(c[i][len[i]-l+k]!=c[j][k])
    			return 0;
    	return 1;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%s",c[i]+1);
    		len[i]=strlen(c[i]+1);
    		b[i]=1<<(i-1);
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			for(int l=min(len[i],len[j]);l>=0;l--)
    				if(ok(i,j,l))
    				{
    					g[i][j]=l;
    					break;
    				}
    	// dfs(1,0);
    	memset(f,0x3f,sizeof(f));
    	int inf=f[0][0];
    	for(int i=1;i<=n;i++)
    		f[b[i]][i]=len[i],t[b[i]][i][1]=i;
    	for(int s=1,le=(1<<n)-1;s<=le;s++)
    	{
    		int con=0;
    		for(int i=1;i<=n;i++)
    			if(s&b[i])
    				con++;
    		for(int i=1;i<=n;i++)
    			if(s&b[i])
    			{
    				for(int j=1;j<=n;j++)
    					if(!(s&b[j]))
    					{
    						int nw=f[s][i]+len[j]-g[i][j],w=(s|b[j]);
    						if(nw<f[w][j])
    						{
    							f[w][j]=nw;
    							for(int k=1;k<=con;k++)
    								t[w][j][k]=t[s][i][k];
    							t[w][j][con+1]=j;
    						}
    						else if(nw==f[w][j])
    						{
    							int t1=0,t2=0,fl=0;
    							for(int k=1;k<=con+1;k++)
    								for(int l=1+g[t[w][j][k-1]][t[w][j][k]];l<=len[t[w][j][k]];l++)
    									s1[++t1]=c[t[w][j][k]][l];
    							for(int k=1;k<=con;k++)
    								for(int l=1+g[t[s][i][k-1]][t[s][i][k]];l<=len[t[s][i][k]];l++)
    									s2[++t2]=c[t[s][i][k]][l];
    							for(int l=1+g[t[s][i][con]][j];l<=len[j];l++)
    								s2[++t2]=c[j][l];
    							for(int k=1;k<=nw;k++)
    							{
    								if(s1[k]<s2[k])
    									break;
    								if(s1[k]>s2[k])
    								{
    									fl=1;
    									break;
    								}
    							}
    							if(fl)
    							{
    								for(int k=1;k<=con;k++)
    									t[w][j][k]=t[s][i][k];
    								t[w][j][con+1]=j;
    							}
    						}
    					}
    			}
    	}
    	// printf("%d
    ",ans);
    	int t1=0,w=(1<<n)-1,ans=1e9;
    	for(int j=1;j<=n;j++)
    	{
    		if(f[w][j]<ans)
    		{
    			ans=f[w][j];
    			int t1=0;
    			for(int k=1;k<=n;k++)
    				for(int l=1+g[t[w][j][k-1]][t[w][j][k]];l<=len[t[w][j][k]];l++)
    					a[++t1]=c[t[w][j][k]][l];
    		}
    		else if(f[w][j]==ans)
    		{
    			int t1=0,fl=0;
    			for(int k=1;k<=n;k++)
    				for(int l=1+g[t[w][j][k-1]][t[w][j][k]];l<=len[t[w][j][k]];l++)
    					s1[++t1]=c[t[w][j][k]][l];
    			for(int k=1;k<=ans;k++)
    			{
    				if(a[k]<s1[k])
    					break;
    				if(a[k]>s1[k])
    				{
    					fl=1;
    					break;
    				}
    			}
    			if(fl)
    				for(int k=1;k<=ans;k++)
    					a[k]=s1[k];
    		}
    	}
    	for(int i=1;i<=ans;i++)
    		printf("%c",a[i]);
    	return 0;
    }
    
  • 相关阅读:
    js判断用户是否在浏览当前页面
    js不改变原对象情况下复制对象object
    js实现jquery中的addClass,removeClass,hasClass方法
    npm install总结 (--savenpm install --save与npm install --save-dev区别及其他相关)
    通过正则实时监听检查input输入,实时反应,不符合不能输入的功能详解
    IE8常见兼容问题及解决方法总结
    javascript中十六进制和ASCII码互相转换
    vue2.0中watch总结:普通监听和深度监听
    js对象数组操作之一:对象数组中对象去重的方法总结
    webpack4配置详细过程及采坑
  • 原文地址:https://www.cnblogs.com/lokiii/p/9644795.html
Copyright © 2011-2022 走看看