• UVa 1607


    链接:

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4482

    题意:

    可以用与非门(NAND)来设计逻辑电路。每个NAND门有两个输入端,输出为两个输入端与非运算的结果。
    即输出0当且仅当两个输入都是1。给出一个由m(m≤200000)个NAND组成的无环电路,
    电路的所有n个输入(n≤100000)全部连接到一个相同的输入x。
    请把其中一些输入设置为常数,用最少的x完成相同功能。输出任意方案即可。

    分析:

    因为只有一个输入x,所以整个电路的功能不外乎4种:常数0、常数1、x及非x。
    先把x设为0,再把x设为1,如果二者的输出相同,整个电路肯定是常数,任意输出一种方案即可。
    如果x=0和x=1的输出不同,说明电路的功能是x或者非x。不妨设x=0时输出0,x=1时输出1。
    现在把第一个输入改成1,其他仍设为0(记这样的输入为1000…0),如果输出是1,则得到了一个解x000…0。
    如果1000…0的输出也是0,再把输入改成1100…0,如果输出是1,则又得到了一个解1x00…0。
    如果输出还是0,再尝试1110…0,如此等等。由于输入全1时输出为1,这个算法一定会成功。


    但是,有一个问题我想不明白,紫书上说可以用二分法来确定1的个数。如果是这样的话,就必须要有
    111...0(1的个数为输出刚好发生变化时的个数,设为p)的输出等于1111...0(1的个数大于p)的输出,
    也就是说,当把0改为1改到输出刚好发生变化时,再把后面的0改为1,输出都不会发生变化。
    如何证明这一点呢?恳请各位大神指教。

    代码:

     1 #include <cstdio>
     2 
     3 struct NAND {
     4     int a, b;
     5     bool o;
     6 } nand[200000+5];
     7 
     8 int n, m;
     9 
    10 bool output(int R){
    11     for(int i = 1; i <= m; i++){
    12         int a = nand[i].a, b = nand[i].b;
    13         a = a < 0 ? -a > R : nand[a].o;
    14         b = b < 0 ? -b > R : nand[b].o;
    15         nand[i].o = !(a && b);
    16     }
    17     return nand[m].o;
    18 }
    19 
    20 int solve(bool aim){
    21     int L = 1, R = n;
    22     while(L < R){
    23         int M = L + (R - L) / 2;
    24         if(output(M) == aim) R = M;
    25         else L = M + 1;
    26     }
    27     return L;
    28 }
    29 
    30 int main(){
    31     int T;
    32     scanf("%d", &T);
    33     while(T--){
    34         scanf("%d%d", &n, &m);
    35         for(int i = 1; i <= m; i++) scanf("%d%d", &nand[i].a, &nand[i].b);
    36         bool all0 = output(n), all1 = output(0);
    37         if(all0 == all1){
    38             for(int i = 0; i < n; i++) printf("0");
    39             printf("
    ");
    40         }
    41         else{
    42             int x = solve(all0);
    43             for(int i = 1; i < x; i++) printf("0");
    44             printf("x");
    45             for(int i = x + 1; i <= n; i++) printf("1");
    46             printf("
    ");
    47         }
    48     }
    49     return 0;
    50 }
  • 相关阅读:
    关键字与标识符
    JAVA 程序的基本语法
    第一个java程序中文乱码以及如何解决
    第一个java程序以及java的运行机制
    java中求余%与取模floorMod的区别
    Volley 框架解析(二)--RequestQueue核心解读
    Volley 源码解析
    Android之Activity系列总结(三)--Activity的四种启动模式
    Android之Activity系列总结(二)--任务和返回栈
    Android之Activity系列总结(一)--Activity概览
  • 原文地址:https://www.cnblogs.com/hkxy125/p/8146091.html
Copyright © 2020-2023  润新知