星象仪

【题目描述】

在寂寞的夜里,星象仪是非常浪漫的东西。但是,你作为一个精神稍微有点不太正常的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 之内。



上午没做这个题 感觉暴力也没法暴力

甚至想到这个是图论 找到一条从0到1到0到1......的最短路


下午才想到 一开始根节点肯定是0

从0到1的最小步数可以求得

假设为k步

那么第k-1步时 根节点输出还是0

也就是说 从此往后 1变成0  0变成1 代价都是1


那么关键就在求从初始状态到1的最小步数上了(如果数列中要求输出1的话)

可以用树状dp做 听简单的dp 就是很难想到


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int s[16444];
int g[16444];
int q[16444];
int top;
int m,a,b,c,z;
int casenum,bu;
string str;
int findmin(int i,int out)
{
    if(i*2>m)
    {
        if(s[i]==0&&out==1)return 1;
        if(s[i]==1&&out==1)return 2;
        return 0;
    }
    int ret=0;
     
    if(out==1)
    if(s[i]==1)return findmin(i<<1,1)+findmin(i<<1|1,1);
    else
    {
        ret=findmin(i<<1,1)+findmin(i<<1|1,0);
        ret=min(ret,findmin(i<<1,0)+findmin(i<<1|1,1));
        return ret;
    }
    return 0;
}
        
int work()
{
    int a,ret=0;
    top=1;
    q[1]=0;

    for(a=0;a<str.length();a++)
    {
        if(str[a]-'0'!=q[top])
        {
            top++;
            q[top]=str[a]-'0';
            ret++;
        }
    }
    if(ret!=0)ret+=bu;
    ret--;
    return ret;
}
    
        
    
int main()
{
    freopen("pla.in","r",stdin);
    freopen("pla.out","w",stdout);
    scanf("%d\n",&casenum);
    while(casenum)
    {
        casenum--;
        scanf("%d\n",&m);
        m--;
        cin>>str;
        for(a=1;a<=m;a++)scanf("%d\n",&s[a]);
        bu=findmin(1,1);
        cout<<work()<<endl;
    }
    return 0;
}
             


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值