链接:
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("\n"); 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("\n"); 47 } 48 } 49 return 0; 50 }
原文地址:https://www.cnblogs.com/hkxy125/p/8146091.html