POJ--1699--Best Sequence【扩展KMP+DFS】

链接:http://poj.org/problem?id=1699

题意:给出n个字符串,求他们相连的最小长度,如果首尾字母相同则可以共用相同部分,比如两个串ABCDEF和DEFGHI,他们相连为ABCDEFGHI,最小长度为9,中间的DEF部分共用了。

思路:由于数据量较小,首先对每两个字符串a,b用扩展KMP求出a连在b之后可以共用的长度,用数组B[i][j]表示第j个字符串连接在第i个字符串后面能共用的最大长度。

1.在扩展KMP函数中求子串a和母串b的公共前缀数组ret[i](子串、母串、公共前缀数组,为了理解方便,我就这么叫了),如果此时ret[i]与strlen(b)-i的值相等,说明b串剩下的部分和a串的前strlen(b)-i个字符完全相等,则这个值就是我们需要的值,因为i是从小到大的,所以如果找到符合的strlen(b)-i值,最先出现的这个值一定是最大的,即可返回,如果最后没有找到符合的值,说明没有b串的后缀和a串的前缀相等,则返回0。

2.找完了数组B中所有值之后,考虑到一个字符串最多只能连在一个字符串的后面,并且身后也最多只能连接一个字符串,而且此题数据较小,可以用dfs来枚举,枚举每个串当首串的情况(即它不连在其他串之后),然后dfs枚举每个串连在它身后的情况,找出这之中的最小值,就是我们需要的答案。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 10100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define LLINF 0x7FFFFFFFFFFFFFFF
#define seed 131
#define MOD 1000000007
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

char a[15][25];
int next[MAXN],ret[MAXN];
int b[15][15],vis[15];
int ans,n;
int ExtendKMP(char a[],char b[]){
    int i,j,k;
    int M = strlen(a);
    int N = strlen(b);
    for(j=0;1+j<M&&a[j]==a[1+j];j++);
    next[1] = j;
    k = 1;
    for(i=2;i<M;i++){
        int Len = k + next[k], L = next[i-k];
        if(L<Len-i){
            next[i] = L;
        }
        else{
            for(j=max(0,Len-i);i+j<M&&a[j]==a[i+j];j++);
            next[i] = j;
            k = i;
        }
    }
    for(j=0;j<N&&j<M&&a[j]==b[j];j++);
    if(j==N)    return N;
    ret[0] = j;
    k = 0;
    for(i=1;i<N;i++){
        int Len = k + ret[k], L = next[i-k];
        if(L<Len-i){
            ret[i] = L;
        }
        else{
            for(j=max(0,Len-i);j<M&&i+j<N&&a[j]==b[i+j];j++);
            ret[i] = j;
            k = i;
        }
        if(ret[i]==N-i) return ret[i];
    }
    return 0;
}
void dfs(int x,int tot,int len){
    if(tot==n){
        if(ans>len) ans = len;
        return ;
    }
    if(len>ans) return ;
    for(int i=0;i<n;i++){
        if(!vis[i]){
            vis[i] = 1;
            dfs(i,tot+1,len+strlen(a[i])-b[i][x]);
            vis[i] = 0;
        }
    }
}
int main(){
    int t,i,j;
    scanf("%d",&t);
    while(t--){
        memset(b,0,sizeof(b));
        memset(vis,0,sizeof(vis));
        ans = INF;
        scanf("%d",&n);
        for(i=0;i<n;i++){
            scanf("%s",a[i]);
        }
        for(i=0;i<n;i++){
            for(j=0;j<n;j++){
                if(i==j)    continue;
                b[j][i] = ExtendKMP(a[i],a[j]);
            }
        }
        for(i=0;i<n;i++){
            vis[i] = 1;
            dfs(i,1,strlen(a[i]));
            vis[i] = 0;
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-26 17:05:32

POJ--1699--Best Sequence【扩展KMP+DFS】的相关文章

POJ 1699 Best Sequence(DFS)

題目鏈接 題意 : 將幾個片段如圖所示方法縮成一個序列,求出最短這個序列. 思路 : 其實我也不知道怎麼做.....看網上都用了DP.....但是我不會.....這個DP不錯,還有用KMP+状压DP做的 1 //1699 2 #include <iostream> 3 #include <stdio.h> 4 #include <string.h> 5 #include <string> 6 7 using namespace std; 8 9 string

POJ 1699 Best Sequence (DFS+预处理)

题意:看那张图就一清二楚了吧, N个序列首位相连(相同的序列部分),得到最短的总序列. 题目链接:http://poj.org/problem?id=1699 ~~~~ 思路就是:将N个序列首尾相连能重合的长度求粗来.然后DFS枚举每种首尾相连的情况. #include<cstdio> #include<cstring> #include<algorithm> #define N 22 #define INF 0x7fffffff using namespace std

poj 1699 Best Sequence (搜索技巧 剪枝 dfs)

题目链接 题意:给出几个基因片段,要求你将它们排列成一个最短的序列,序列中使用了所有的基因片段,而且不能翻转基因. 分析:先计算出add数组,再dfs枚举. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <cstdio> 6 #include <vector> 7 #include <al

poj 1699 Best Sequence(dfs)

http://poj.org/problem?id=1699 题意:给出n个只含A,C,G,T的字符串,要求能把这n个字符串组合起来的最短长度. 思路:预处理一下,a[i][j]表示将第j个字符串连接到第i个字符串后面增加的长度,那么我们需要找出这样一个序列1,2....n满足a[1][2] + a[2][3] + ...+a[n-1][n]的最小值.DFS就OK了,任选一个字符串作为起点进行dfs,求出所有的情况后得到最小的长度. #include <stdio.h> #include &l

poj 1699 Best Sequence

http://poj.org/problem?id=1699 题意:给你n个长度为L的序列,求包含这几个序列的最短长度. 先预处理每两个序列之间的关系,然后dfs枚举就行. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 500 5 using namespace std; 6 const int inf=1<<30; 7 8 char str[ma

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 &

(简单) POJ 1961 Period,扩展KMP。

Description For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want to know whether the prefix is a periodic string. That is, for each i (2 <= i <= N) we want to know the larges

hdu2328 Corporate Identity 扩展KMP

Beside other services, ACM helps companies to clearly state their "corporate identity", which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently asked ACM for

[kuangbin带你飞]专题十六 KMP &amp; 扩展KMP &amp; Manacher :G - Power Strings POJ - 2406(kmp简单循环节)

[kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher G - Power Strings POJ - 2406 题目: Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of