/**//* 题意:给出一些病毒串,一个原串,问怎么调整原串的顺序使得跟最多的病毒串匹配
抄解题报告: 自动机+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
搜索
最新评论
|
|