 /**//*
题意:给出一些病毒串,一个原串,问怎么调整原串的顺序使得跟最多的病毒串匹配

抄解题报告:
自动机+DP。设主串有na个A、nc个C、ng个G、nt个T,于是题意转化为用na个A、
nc个C、ng个G、nt个T生成一个新串,使模式串匹配次数最大。先将模式串生成自动机
〔trie图〕,然后在这上面进行DP,状态可表示为dp[d,s],d为自动机状态,
s表示由ma个A、mc个C、mg个G、mt个T的生成串
〔s可表示为ma*(nc+1)*(ng+1)*(nt+1)+mc*(ng+1)*(nt+1)+mg*(nt+1)+mt〕,
转移为O(4),总复杂度O(500*11^4*4)
那种表示方法就是变进制吧

直接DP(root,s)会超时
Qinz说这题卡时紧
我用他的那种dfs才能过,他是先dfs枚举出状态,然后对这个状态递推计算,好快

比较神奇,不用管顺序的,就记录个数
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>

using namespace std;

const int MAXN = 520;

struct Node
  {
Node *ch[4] , *next;
int id , match;
};

Node nodes[MAXN] , *Trie , *SuperRoot;
int alloc;

Node *newNode()
  {
memset(&nodes[alloc] , 0 , sizeof(nodes[0]));
nodes[alloc].id = alloc;
return &nodes[alloc++];
}

//int getID(char ch)
//{
// if(ch=='A')return 0;
// if(ch=='C')return 1;
// if(ch=='G')return 2;
// if(ch=='T')return 3;
//}

int getID[200];

void insert(Node * &root, char *s)
  {
if(*s == 0)root->match++;
else
 {
int id = getID[*s];
if(root->ch[id] == 0)root->ch[id] = newNode();
insert(root->ch[id],s+1);
}
}

void buildTrie()
  {
for(int i = 0 ; i<4; i++)
SuperRoot->ch[i] = Trie;
Trie->next = SuperRoot;
queue<Node*>Q;
Q.push(Trie);
while(!Q.empty())
 {
Node *p = Q.front() ; Q.pop();
for(int i = 0 ; i<4; i++)
 {
if(p->ch[i])
 {
p->ch[i]->next = p->next->ch[i];
p->ch[i]->match += p->next->ch[i]->match;//要加这个
Q.push(p->ch[i]);
}
else p->ch[i] = p->next->ch[i];
}
}
}

int val[5];
int num[5];
int dp[MAXN][MAXN*30];


int DP(Node *root, int s)//当前在节点root 剩下可用的字符s 最后能获得的最大值
  {
if(s==0)return root->match;
int id = root->id;
int &ans = dp[id][s];
if(ans != -1)return ans;//
ans = 0;

int _s = s , t = 1;
for(int i = 3 ; i>= 0;s/=(num[i]+1),i--)
 {
if(s % (num[i]+1) == 0)continue;
ans = max(ans,DP(root->ch[i] , _s - val[i]) );
}
return ans += root->match;//root此时有占一个字符,但不是属于s的
}

int _num[4];

void dfs(int s , int deep)
  {
if(deep == 4)//dp[i][s] 在节点i处,剩余s个字符的最大值,节点i不占字符
 {
for(int i = 1 ; i < alloc ; i++)
for(int j = 0 ; j < 4; j++)
if(_num[j])
 {
int jj = nodes[i].ch[j]->id;
dp[i][s] = max(dp[i][s] , dp[jj][s-val[j]] + nodes[jj].match);//
}
return ;
}

for(int i = 0 ; i <= num[deep] ; i++ , s+=val[deep])
 {
_num[deep] = i;
dfs(s,deep+1);
}
}

int main()
  {

#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif
getID['A'] = 0;
getID['C'] = 1;
getID['G'] = 2;
getID['T'] = 3;
char str[100];
for(int n ,t = 1;scanf("%d",&n) ,n ; t++)
 {
alloc = 0 ;
SuperRoot = newNode();
Trie = newNode();

for(int i = 0 ; i < n; i++)
 {
scanf("%s",str);
insert(Trie,str);
}

buildTrie();

scanf("%s",str);
memset(num,0,sizeof(num));
for(int i = 0 ; str[i] ; i++)
 {
num[getID[str[i]]]++;
}

int total = 1;
for(int i = 0 ; i < 4; i++)
 {
total *= (num[i]+1);
}
num[4] = 0;
val[4] = 1;
for(int i = 3 ; i>=0 ;i--)
 {
val[i] = val[i+1]*(num[i+1]+1);
}
val[4] = total;

for(int i = 0 ; i < alloc ; i++)
for(int j = 0 ; j <= total ; j++)
dp[i][j] = 0;//-1;
dfs(0,0);
printf("Case %d: %d\n",t,dp[1][total-1]);//DP(Trie,total-1));
}
return 0;
}

|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|