星象仪
(pla.pas/c/cpp)
题目描述
在寂寞的夜里,星象仪是非常浪漫的东西。但是,你作为一个精神稍微有点不太正常的Geek,
把原本正常的星象仪改造得像电报发送器一样。当然,你这个的构造还要更加奇葩一点。具
体来说,你的星象仪是一棵满二叉树,二叉树的节点都是有两个输入端和一个输出端的AND
门或者OR 门。它们输入和输出的信号都是只是0 或者1。它们会接受子节点的输出信号,
然后将这两个信号进行AND 运算或者OR 运算作为自己的输出。然后,根节点的输出信号
就是整个星象仪的输出信号。叶节点的输入信号是由你来调整的,如果二叉树有K 层,那
么你显然有2K 个输入信号可以调整。调整一次当然只能改变一个输入信号。如左图所示,
这就是一台你改造过之后的星象仪。根据你的设定,在一开始所有的输入端的输入信号都是
0。现在你希望用星象仪得到一串信号,为此,你需要不停地调整输
入。假定你想要用左图中的星象仪得到输出信号000111,一种可行的方案是0001→0011→
1100→1111→1010→0101,但是这样你要调整14 次输入信号。更加方便的方式是0000→
0000→0000→0101→0101→0101,这样你总计只需要调整2次输入信号。由于调整输入信号
是一件非常麻烦的事情,现在你希望知道对于一台给定的星象仪,如果想要得到一串给定的
信号,至少需要调整多少次输入。
输入格式
输入文件包含多组测试数据。第一行有一个整数T,表示测试数据的组数。
测试数据的第一行是一个正整数 N,表示输入信号的数目。保证N 是2 的整数次幂。
第二行含有一个由 0 和1 组成的字符串S,表示你想要得到的信号。
第三行包含 N – 1 个整数,按照层次遍历顺序给出满二叉树的每个节点。整数只会是0或者1。
0 表示二叉树的这个位置是一个OR 门,1 表示是一个AND 门。
对于每组测试数据,在单独的一行内输出结
样例输入
2
4
010101
0 0 0
4
111111
1 1 1
样例输出
5
4
数据范围与约定
对于30% 的数据,N≤16,S 的长度在100 之内。
对于 100% 的数据,T≤100,N≤8192,S 的长度在 10000 之内。
思路:首先,普及一下and,or 其实就是交集并集的关系
当且仅当两个数都是1,and的值为1,
两个数中存在1,or的值为1,
看到二叉树,心中莫名高兴,不用谢邻接表了
付题目中的图
如果使1号点输出1,那么2,3号点都要为1,
二号点为1,那么,4,5号点有一个为1,
同理,6,7号点有一个为1,
那么,从全0状态到输出1,只需要更改2个点
然后,从输出1到输出0,更改的点数一定小于等于从全0状态到输出1更改的点数
然后呢?
树p
对于一个全0状态的树,如果要输出1,那么,对于每一个节点,
如果是and,则选择他的所有儿子都为1的方案数,
如果是or,则选择它的儿子中为1的方案数的最小值
(结果为第一次变换是使用)
然后,对于一个输出1 的树的每一个节点,
如果是and,则选择将其中一个节点变为0,
如果是or,则将其原来选择变为1的节点变为0,
(结果为以后的变换时使用)
附代码:
program ex02; var tree,a:array[0..100000] of longint; ss:ansistring; t,n,i:longint; procedure init; var i:longint; begin readln(n); readln(ss); for i:=1 to n-1 do begin read(tree[i]); end; end; function min(a,b:longint):longint; begin if a<b then exit(a); exit(b); end; function dfs2(root:longint):longint; //第二次树p begin if root>=n then exit(1); if tree[root]=0 then begin if a[root]=a[root*2] then dfs2:=dfs2(root*2) else dfs2:=dfs2(root*2+1); end else if tree[root]=1 then begin dfs2:=min(dfs2(root*2),dfs2(root*2+1)); end; end; function dfs1(root:longint):longint; //第一次树p begin if root>=n then exit(1); if tree[root]=0 then begin dfs1:=min(dfs1(root*2+1),dfs1(root*2)); a[root]:=dfs1; end else if tree[root]=1 then begin dfs1:=dfs1(root*2)+dfs1(root*2+1); a[root]:=dfs1; end; end; procedure doit; var i,k1,k2,ans:longint; flag:boolean; begin k1:=dfs1(1); k2:=dfs2(1); flag:=true; ans:=0; ss:='0'+ss; for i:=2 to length(ss) do //计算方案数 begin if ss[i]<>ss[i-1] then if (ss[i]='1') and (flag=true) then //如果是第一变换 begin flag:=false; ans:=ans+k1; end else //以后的变换 begin ans:=ans+k2; end; end; writeln(ans); end; begin assign(input,'pla.in'); reset(input); assign(output,'pla.out'); rewrite(output); readln(t); for i:=1 to t do begin fillchar(a,sizeof(a),0); init; doit; end; close(input); close(output); end.