[SCU 4501] DNA序列 (状压DP)

SCU - 4501

给定若干个DNA序列,求最短包含所有序列的长度

包含不一定是连续包含,可以不是子串



状压DP

依次构造每一位

把每个字符串走到的位置标记一下,压成6进制数

然后每个状态拓展一个字符串

然后同时拓展其他所有下一位与其相同的串

然后把状态丢到队列里转移,当每个串都走到结尾时输出答案

可以保证答案最多不超过40

时间复杂度 O(ans?lenN)

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <queue>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) (a*a)

struct data
{
    int mask,res;
    data(int tm,int tr):mask(tm),res(tr){}
};
int N;
char inpt[10][10];
int tlen[10];
int buff[10];

int encode(int*);
int* decode(int);
bool check(int*);

int main()
{
    int T;
    scanf("%d", &T);
    for(int ck=1; ck<=T; ck++)
    {
        scanf("%d", &N);
        for(int i=0; i<N; i++)
        {
            scanf(" %s", inpt[i]);
            tlen[i]=strlen(inpt[i]);
        }
        queue<data> que;
        set<int> vis;
        que.push(data(0,0));
        while(que.size())
        {
            data &u=que.front();
            int *used=decode(u.mask);
            if(check(used)){printf("%d\n", u.res);break;}
            bool ban[10]={0};
            for(int i=0; i<N; i++)
            {
                int temp[10];
                if(used[i]>=tlen[i]||ban[i]) continue;
                char nxt=inpt[i][used[i]];
                for(int j=0; j<N; j++)
                {
                    temp[j]=used[j];
                    if(temp[j]>=tlen[j]) continue;
                    if(inpt[j][temp[j]]==nxt)
                    {
                        temp[j]++;
                        ban[j]=1;
                    }
                }
                int nm=encode(temp);
                if(vis.find(nm)!=vis.end()) continue;
                que.push(data(nm, u.res+1));
                vis.insert(nm);
            }
            que.pop();
        }
        while(que.size()) que.pop();
    }
    return 0;
}

int encode(int buff[])
{
    int res=0;
    for(int i=N-1; i>=0; i--) res=res*6+buff[i];
    return res;
}

int* decode(int num)
{
    for(int i=0; i<N; i++)
    {
        buff[i]=num%6;
        num/=6;
    }
    return buff;
}

bool check(int cntc[])
{
    for(int i=0; i<N; i++) if(cntc[i]<tlen[i]) return 0;
    return 1;
}
时间: 2024-11-04 20:58:15

[SCU 4501] DNA序列 (状压DP)的相关文章

HDOJ 1560 DNA sequence 状压dp 或 IDA*

http://acm.hdu.edu.cn/showproblem.php?pid=1560 题意: 给不超过8个子串,每个子串最多5位,且都只包含ATCG,求最短的母串长度. 分析: 又是上个月写的,所以有点忘了..正解是IDA*.然后可以状压dp,记忆化搜索.dp[i],i用6进制表示,每位表示对应的子串匹配那么多长度所需要的最短母串长度.比如两个子串,13=2*6^1+1*6^0,dp[13]就表示第一个串匹配了第一位,第二个串匹配前两位所需要的最短母串长度. 状态讲完了,不过实际上程序里

POJ 1795 DNA Laboratory (贪心+状压DP)

题意:给定 n 个 字符串,让你构造出一个最短,字典序最小的字符串,包括这 n 个字符串. 析:首先使用状压DP,是很容易看出来的,dp[s][i] 表示已经满足 s 集合的字符串以 第 i 个字符串结尾,他很容易就求得最短长度,但是这个字符串怎么构造呢, 由于要字典序最小,所以就不好搞了,挺麻烦的,所以我们利用贪心的思路,我们可以这样定义,dp[s][i] 表示已经满足 s 集合的字符串以 第 i 个字符串开头, 从后向前放,状态转移方程为:dp[s|(1<<i)][i] = min{ dp

poj 1699 Best Sequence(AC自动机+状压DP)

题目链接:poj 1699 Best Sequence 题目大意:给定N个DNA序列,问说最少多长的字符串包含所有序列. 解题思路:AC自动机+状压DP,先对字符串构造AC自动机,然后在dp[s][i]表示匹配了s,移动到节点i时候的最短步数. #include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include &

[hdu 4899]14年多校第四场C Hero meet devil 状压DP

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 122    Accepted Submission(s): 49 Problem Description There is an old country and the king fell in love with a devil. The devil always asks th

【BZOJ2064】分裂 状压DP

[BZOJ2064]分裂 Description 背景:和久必分,分久必和...题目描述:中国历史上上分分和和次数非常多..通读中国历史的WJMZBMR表示毫无压力.同时经常搞OI的他把这个变成了一个数学模型.假设中国的国土总和是不变的.每个国家都可以用他的国土面积代替,又两种可能,一种是两个国家合并为1个,那么新国家的面积为两者之和.一种是一个国家分裂为2个,那么2个新国家的面积之和为原国家的面积. WJMZBMR现在知道了很遥远的过去中国的状态,又知道了中国现在的状态,想知道至少要几次操作(

【状压dp】Most Powerful

[ZOJ3471]Most Powerful Time Limit: 2 Seconds      Memory Limit: 65536 KB Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappe

ZOJ3802 Easy 2048 Again (状压DP)

ZOJ Monthly, August 2014 E题 ZOJ月赛 2014年8月 E题 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5334 Easy 2048 Again Time Limit: 2 Seconds      Memory Limit: 65536 KB Dark_sun knows that on a single-track road (which means once he passed this

zoj3802:easy 2048 again(状压dp)

zoj月赛的题目,非常不错的一个状压dp.. 题目大意是一个一维的2048游戏 只要有相邻的相同就会合并,合并之后会有奖励分数,总共n个,每个都可以取或者不取 问最终得到的最大值 数据范围n<=500 , a[i]={2,4,8,16}: 分析: 首先明确一下自动合并的意思,比如原有 8,4,2,进入一个2 就会变成16 所以我们需要记录前面的所有数字..计算了一下发现最大情况,500个16会合成4096 =2^12 显然全部记录是不可能的.那么怎么处理呢 我们发现,只有递减的序列才有可能向前合

codeforces 453 B Little Pony and Harmony Chest (状压dp)

题目大意: 需要你构造一个b数组.使得b数组中的所有元素互质. 而且使得b数组与a数组中的每个对应下标元素的差值和最小. 思路分析: 考虑到 a中所有元素都是 0 - 30. 所以b中的元素也只可能在 0 - 59. 因为如果b 选择60的话,结果和1是一样的,而且b序列中 1 可以重复出现很多次. 因为gcd (1,x) = 1.. 所以们首先把2 - 59中的所有素数处理出来,只有17个. 然后状压这些素数因子. dp[i] [s] [0] 表示 递推到第 i 个位置 达到素数因子为s的状态