题意:给定若干个DNA(由AGCT组成)串,求一个能够包含所有给定串的长串的最小长度。比如包含如下五个串:‘TCGG', 'GCAG', 'CCGC', 'GATC' 和 'ATCG的结果是CCGCAGATCGG。
思路:先用一个数组over[i][j]记录第i个串在第j个串前面时的最大重复字符数。然后搜索串的不同排列方式(相当与对不同串的前后进行全排列),求出不同方式的最短总串长度即可。
但是,怎么做都会WA,看了discuss知道错误出现在串有包含情况的数据中。但是题目并没有说不允许串的包含,不明所以。比如两个串“CC”和“ACCA”,按照题意应该“ACCA”就符合的嘛,但是这组数据偏偏要输出6,也就是求over[i][j]的时候,i不能包含j,也就是当第i个串的长度(leni)大于等于第j个串的长度(lenj)时,第i个串需要从第leni-lenj+1的位置开始匹配。这有点诡异吧!
#include <stdio.h> #include <string.h> #define min(a,b) ((a)<(b)?(a):(b)) #define N 15 #define M 25 #define INF 0x3fffffff char s[N][M]; int over[N][N],seq[N],visited[N]; int n,m,T,res,sumlen; int test_overlap(int i,int j){ char a[M],b[M]; int lena,lenb,flag; strcpy(a,s[i]); strcpy(b,s[j]); lena = strlen(a); lenb = strlen(b); if(lena> lenb)//按照我之前的做法i直接赋值为0 i = lena-lenb+1; else i = 0; for(;i<lena;i++){ for(j = flag = 0;j<lenb&&j+i<lena;j++) if(a[i+j] != b[j]){ flag = 1; break; } if(!flag) return j; } return 0; } void dfs(int depth){ int i,temp; if(depth == n){ for(i = temp = 0;i<n-1;i++) temp += over[seq[i]][seq[i+1]]; res = min(res,sumlen-temp);//一次排列的结果,所有字符的综合减去这种排列一共消掉的字符数 return; } for(i = 0;i<n;i++) if(!visited[i]){ seq[depth] = i;//seq保存全排列的数字 visited[i] = 1; dfs(depth+1); visited[i] = 0; } } int main(){ freopen("a.txt","r",stdin); scanf("%d",&T); while(T--){ int i,j,k; res = INF; memset(visited,0,sizeof(visited)); scanf("%d",&n); for(i = sumlen = 0;i<n;i++){ scanf("%s",s[i]); sumlen += strlen(s[i]); } for(i = 0;i<n;i++) for(j = 0;j<n;j++) if(i != j) over[i][j] = test_overlap(i,j); dfs(0); printf("%d\n",res); } return 0; }