星象仪
(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.

 

posted on 2016-11-03 19:51  艾路雷朵  阅读(387)  评论(0编辑  收藏  举报