您的位置:首页 > 其它

HDU 3341 Lost's revenge

2016-05-19 21:32 204 查看
给定n个模式串和一个目标串,求将目标串重排列后所能包含的最多的模式串个数。可以开个dp[s][a][c][g][t]来记录状态转移,s为结点状态,但是a,c,g,t的值范围为[0,40],很明显数组爆了,于是有个很神奇的方法,可以利用状态压缩把状态压成最多11*11*11*11的大小来标记a,c,g,t. num[4]来记录a,c,g,t出现的次数。bits[4]代表对应的权值,那么bits[0]=(num[1]+1)*(num[2]+1)*(num[3]+1),bits[1]=(num[2]+1)*(num[3]+1),bits[2]=(num[3]+1),bits[3]=1;
假设枚举a,b,c,d时对应的下标为A,B,C,D。那么此时对应的状态status=num[A]*bits[A]+num[B]*bits[B]+num[C]*bits[C]+num[D]*bits[D].那么只需要dp[s][11<<4]来记行dp就可以了,最终的答案为最大的

dp[i][status],i为所有结点,status=num[0]*bits[0]+num[1]*bits[1]+num[2]*bits[2]+num[3]*bits[3].我觉得应该是a,b,c,d对应在定义好的一段上吧?我也不是十分理解...代码如下

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int INF=1e9;
const int MOD=20090717;

struct Tree
{
int next[510][26],end[510],fail[510];
int L,root;
int newnode()
{
for(int i=0;i<26;i++)
{
next[L][i]=-1;
}
end[L++]=0;
return L-1;
}
void init()
{
L=0;
root=newnode();
}
int getch(char ch)
{
if(ch=='A') return 0;
else if(ch=='G') return 1;
else if(ch=='C') return 2;
else if(ch=='T') return 3;
}
void insert(char *s)
{
int len=strlen(s);
int p=root;
for(int i=0;i<len;i++)
{
int id=getch(s[i]);
if(next[p][id]==-1)
{
next[p][id]=newnode();
}
p=next[p][id];
}
end[p]++;
}
void build()
{
queue<int>q;
int p=root;
fail[root]=root;
for(int i=0;i<26;i++)
{
//	printf("%d %d %d\n",i,p,next[p][i]);
if(next[p][i]==-1)
{
next[p][i]=root;
}
else
{
fail[next[p][i]]=root;
q.push(next[p][i]);
}
}
while(!q.empty())
{
p=q.front();
q.pop();
if(end[fail[p]]) end[p]+=end[fail[p]];
for(int i=0;i<26;i++)
{
if(next[p][i]==-1)
{
next[p][i]=next[fail[p]][i];
}
else
{
fail[next[p][i]]=next[fail[p]][i];
q.push(next[p][i]);
}
}
}
}
int dp[510][11*11*11*11+2];
int num[4],bit[4];
void solve(char *s)
{
int len=strlen(s);
memset(num,0,sizeof(num));
for(int i=0;i<len;i++)
{
num[getch(s[i])]++;
}
bit[0]=(num[1]+1)*(num[2]+1)*(num[3]+1);
bit[1]=(num[2]+1)*(num[3]+1);
bit[2]=(num[3]+1);
bit[3]=1;
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
for(int A=0;A<=num[0];A++)
{
for(int B=0;B<=num[1];B++)
{
for(int C=0;C<=num[2];C++)
{
for(int D=0;D<=num[3];D++)
{
int s=A*bit[0]+B*bit[1]+C*bit[2]+D*bit[3];
for(int i=0;i<L;i++)
{
if(dp[i][s]>=0)
for(int k=0;k<4;k++)
{
if(k==0&&A==num[0]) continue;
if(k==1&&B==num[1]) continue;
if(k==2&&C==num[2]) continue;
if(k==3&&D==num[3]) continue;
dp[next[i][k]][s+bit[k]]=max(dp[next[i][k]][s+bit[k]],dp[i][s]+end[next[i][k]]);
}
}
}
}
}
}
int status=num[0]*bit[0]+num[1]*bit[1]+num[2]*bit[2]+num[3]*bit[3];
int ans=0;
for(int i=0;i<L;i++)
{
ans=max(ans,dp[i][status]);
}
printf("%d\n",ans);
}
/*void query(char *s)
{
int len=strlen(s);
int p=root,ans=0;
memset(cnt,0,sizeof(cnt));
memset(last,-1,sizeof(last));
for(int i=0;i<len;i++)
{
int id=s[i]-'a';
p=next[p][id];
int temp=p;
while(temp!=root)
{
cnt[0][temp]++;
if(i-last[temp]>=deep[temp])
{
cnt[1][temp]++;
last[temp]=i;
}
temp=fail[temp];
}
}
}*/
/*	void debug()
{
for(int i = 0;i < L;i++)
{
printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
for(int j = 0;j < 26;j++)
printf("%2d",next[i][j]);
printf("]\n");
}
}*/
};
Tree ac;
char s[22],str[50];
int main()
{
int cas=1;
int n;
while(~scanf("%d",&n))
{
if(n==0) break;
ac.init();
for(int i=0;i<n;i++)
{
scanf("%s",s);
ac.insert(s);
}
scanf("%s",str);
ac.build();
printf("Case %d: ",cas++);
ac.solve(str);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: