[关闭]
@zzzc18 2017-05-12T12:35:36.000000Z 字数 1516 阅读 548

2017.5.3 tree

TEST


最优构造树(Tree)

给出N个长度为L的单词,N为2的整数次幂,那么我们可以构造出一棵树,把给出的N个单词作为树的叶子,其他每个树上的节点也都是一个长度为L的单词,我们定义一条边的代价为它连接的两个节点所代表的单词对位比较不同位的数目,整棵树的代价为所有边的代价和。

             AC

     AC              AC

  AB     AC      BC     AC

上面这棵树的代价和就是2。(脑补箭头吧)

给出N个单词,求最优构造树的最小代价。

输入格式:

第一行两个整数N和L,N <= 1024, L <= 1000
接下来N行每行一个单词。
多组数据,以0 0结束。

输出格式:

一个数表示最小代价。

样例输入:

4 3
AAG
AAA
GGA
AGA

4 3
AAG
AGA
AAA
GGA

4 3
AAG
GGA
AAA
AGA

4 1
A
R
A
R

2 1
W
W

2 1
W
Y

1 1
Q

0 0

样例输出:

3
4
4
2
0
1  
0

Solution

观察后发现,每一位都是独立于别的位的

可以每一位进行状态压缩DP解决

节点编号*2为左节点,*2+1为右节点
数组里的数是状态压缩的字母可能
当左右儿子有可能字母相同时,肯定选这个相同的字母,代价就是左右儿子之和(未生成新的代价)

  1. if(opt[i<<1][j] & opt[(i<<1)+1][j]){
  2. opt[i][j]=opt[i<<1][j] & opt[(i<<1)+1][j];
  3. ans[i][j]=ans[i<<1][j] + ans[(i<<1)+1][j];
  4. }

当左右儿子完全没有可能的字母时,把它存下来,代价+1;

  1. else{
  2. opt[i][j]=opt[i<<1][j] | opt[(i<<1)+1][j];
  3. ans[i][j]=ans[i<<1][j] + ans[(i<<1)+1][j]+1;
  4. }

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define MAXS 1005
  5. using namespace std;
  6. int n,l,depth;
  7. char s[MAXS];
  8. long long opt[2050][1005];
  9. int ans[2050][1005];
  10. void PRE(){
  11. int i,j;
  12. for(i=1;i<=2*n;i++){
  13. for(j=0;j<l;j++){
  14. opt[i][j]=ans[i][j]=0;
  15. }
  16. }
  17. }
  18. void GO(int i,int x){
  19. opt[i+n-1][x]^=1<<(s[x]-'A');
  20. }
  21. void solve(){
  22. int i,j;
  23. for(i=n-1;i>=1;i--){
  24. for(j=0;j<l;j++){
  25. if(opt[i<<1][j] & opt[(i<<1)+1][j]){
  26. opt[i][j]=opt[i<<1][j] & opt[(i<<1)+1][j];
  27. ans[i][j]=ans[i<<1][j] + ans[(i<<1)+1][j];
  28. }
  29. else{
  30. opt[i][j]=opt[i<<1][j] | opt[(i<<1)+1][j];
  31. ans[i][j]=ans[i<<1][j] + ans[(i<<1)+1][j]+1;
  32. }
  33. }
  34. }
  35. int tot=0;
  36. for(i=0;i<l;i++){
  37. tot+=ans[1][i];
  38. }
  39. printf("%d\n",tot);
  40. }
  41. int main(){
  42. freopen("tree.in","r",stdin);
  43. freopen("tree.out","w",stdout);
  44. while(scanf("%d%d",&n,&l)!=EOF){
  45. if(n==0 && l==0)return 0;
  46. int i;
  47. PRE();
  48. for(i=1;i<=n;i++){
  49. scanf("%s",s);
  50. for(int j=0;j<l;j++){
  51. GO(i,j);
  52. }
  53. }
  54. solve();
  55. }
  56. return 0;
  57. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注