HDU_1560
一种可行的思路是迭代加深搜索,只要在不断增加递归深度限制时第一次出现生成了规定的字符串时,这个深度就是最优的深度了。
接下来就是考虑如何剪枝了,一种明显的思路就是记录当前每个字符串还差多少位补全,然后取最大的差距,如果剩下的可以构造的字符数小于最大的差距的话,那么就可以剪枝了。但这个剪枝还不够强,比如这个数据就会很慢
8
AAAAA
GGGGG
CCCCC
TTTTT
TTTAA
AAATT
CCGGG
GGGCC
,根据这个数据就会想到一个更好的剪枝,我们考虑至少还需要多少个A,至少还需要多少个T以及C、G,然后把4项之和作为前面所说的“最大的差距”,用这个作为剪枝的条件就比较快了,上面那组数据就几乎瞬出了。
至于至少需要多少个A,我们可以先算一下各个字符串还需要多少个A,然后取最大值,至于T、C、G也是一样的。
#include<stdio.h> #include<string.h> #include<algorithm> #define MAXN 8 #define MAXL 5 int N, n[MAXN], a[MAXN][MAXL]; char ch[128]; void init() { int i, j; char b[10]; scanf("%d", &N); for(i = 0; i < N; i ++) { scanf("%s", b); n[i] = strlen(b); for(j = 0; j < n[i]; j ++) a[i][j] = ch[b[j]]; } } int Max(int *x) { int i, j, h[4], max[4] = {0}; for(i = 0; i < N; i ++) { memset(h, 0, sizeof(h)); for(j = x[i]; j < n[i]; j ++) ++ h[a[i][j]]; for(j = 0; j < 4; j ++) max[j] = std::max(max[j], h[j]); } return max[0] + max[1] + max[2] + max[3]; } int dfs(int d, int *ix) { if(Max(ix) > d) return 0; if(d == 0) return 1; int i, j, x[MAXN]; for(i = 0; i < 4; i ++) { for(j = 0; j < N; j ++) { if(ix[j] < n[j] && a[j][ix[j]] == i) x[j] = ix[j] + 1; else x[j] = ix[j]; } if(dfs(d - 1, x)) return 1; } return 0; } void solve() { int dep, ini[8] = {0}; for(dep = 1; !dfs(dep, ini); dep ++); printf("%d\n", dep); } int main() { int t; ch['A'] = 0, ch['T'] = 1, ch['C'] = 2, ch['G'] = 3; scanf("%d", &t); while(t --) { init(); solve(); } return 0; }