Problem G – Gates of uncertainty(与非门的测试)

原题: https://vjudge.net/problem/Gym-101889G

题意:

有多个与非门连接而成的二叉树形电路,现在有几个门坏了,即无论输入什么都输出1或0,你已经知道了坏的具体情况,问有多少种输入方式使门一的输出错误(即如果所有门都正常时的输出和现在的输出不符)
在这里插入图片描述
在这里插入图片描述
解析:

第一眼就看出来是个dp,但是怎么构造想了一会。

dp[i][f][out] 表示第i个门正确性为f时输出为out的方案数,例如:dp[3][1][0] 表示第3个门正确的输出0的方案数

答案数为dp[1][0][0]+dp[1][0][1]

那么其实转换就比较方便了,先用与非算出如果没有出错时的输出,dp[i][1][x]的原来为x,dp[i][0][x]的原来为!x;再用现在的状况计算出输出,dp[i][f][0]为0,dp[i][f][1]为1

如果两个输出相同就归结到dp[i][1][x],否则dp[i][0][x]

#include<bits/stdc++.h>
using namespace std;
#define debug(x) printf("# %d\n",x)
#define pill pair<int,int>
#define LL long long
int read(){int a;scanf("%d",&a);return a;}
const int N=1e5+5;
const LL mod=1e9+7;
int f[N];
LL dp[N][2][2];
int son[N][2];

int door(int a,int b){if(a==1&&b==1)return 0;return 1;}

void dfs(int p){
    int l=son[p][0],r=son[p][1];
    if(l)dfs(l);if(r)dfs(r);

    for(int i=0;i<2;i++){//正确
        for(int j=0;j<2;j++){//输入
            LL _1=dp[l][i][j];
            if(!_1)continue;
            for(int k=0;k<2;k++){
                for(int h=0;h<2;h++){
                    LL _2=dp[r][k][h];
                    if(!_2)continue;
                    int a=j,b=h;
                    if(!i)a=!a;if(!k)b=!b;
                    int outpre=door(a,b),outnow=door(j,h);
                    if(f[p]!=-1)outnow=f[p];
                    if(outnow==outpre){
                        dp[p][1][outnow]=(dp[p][1][outnow]+_1*_2%mod)%mod;
                    }
                    else{
                        dp[p][0][outnow]=(dp[p][0][outnow]+_1*_2%mod)%mod;
                    }
                }
            }
        }
    }
}

int main(){
    int n=read();
    for(int i=1;i<=n;i++){
        son[i][0]=read(); son[i][1]=read(); f[i]=read();
    }
    dp[0][1][1]=dp[0][1][0]=1;
    dfs(1);
    LL ans=(dp[1][0][1]+dp[1][0][0])%mod;
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/83146007