UVa #1607 Gates (例题8-14)

86 篇文章 0 订阅

完全没意料到的AC啊。。这么顺利。。最近人品爆发


Rujia的分析以及分析的方法值得仔细学习。。对于题目,考虑一下不同输入会出现的情况,分类、归纳,找到临界处,简化问题


这道题把四种可能的情况列出,规律就是输出是常数0、1,x和!x中的一个。

如果是常数,则输入可以任意。如果是x或!x,那么 x 等于 0 或 1 时的输出不同,所以从 00...00 开始,逐位改为 1 ,直到 11...11 ,中途一定有某一个时刻输出值会改变。那么在那个位置上放上 x 即可。这里顺便证明了只要有一个输入是 x 就足够了。这个有点像判断一元一次函数是否穿过横轴,一种方法就是找出两个 y 值符号相反的函数上的点。


逐位扫描固然ok,不过二分法是不是一定可行呢?我觉得二分法肯定是能得到解,但是不知道会不会存在这么一种情况:在 k 位置放上 x 时可以得到一个解,但是在之后的某一个位置 p 上再放上 x ,两个x的作用相互抵消,导致二分法判断时会将这种情况认定为 p+1 位置之前没有解。我还找不出这种情况的例子,而且这种情况并不影响二分法的高效性。只是不知道能不能证明这种情况的可能性呢?


这次还试了试宏,NAND(x,y)输出x和y的与非值。


Run Time: 0.315s

#define UVa  "LT8-14.1607.cpp"
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<algorithm>
#include<cstdio>

using namespace std;

#define NAND(x, y) (!(x&&y));

//Global Variables. Reset upon Each Case!
const int maxm = 200000 + 10, maxn = 100000 + 10;
int ones[maxn], zeros[maxn];
int T, n, m;
int gate_input[maxm][2];
/

int net_output(int* net_input) {
    int gate_output[maxm];
    for(int i = 0; i < m; i ++) {
        int x = gate_input[i][0], y = gate_input[i][1];
        int input1, input2;
        if(x < 0) input1 = net_input[abs(x) - 1];
        else      input1 = gate_output[x-1];
        if(y < 0) input2 = net_input[abs(y) - 1];
        else      input2 = gate_output[y-1];
        gate_output[i] = NAND(input1, input2);
    }
    return gate_output[m-1];
}

void print_repeat(int a, int l) {
    for(int i = 0; i < l; i ++) printf("%d", a);
}

int solve() {
    int input[maxn];
    memset(input, 0, sizeof(input));
    int initial_output;
    initial_output = net_output(input);
    int l = 0, r = n;
    while(l < r) {
        int mid = l + (r-l)/2;
        memset(input, 0, sizeof(input));
        memcpy(input, ones, (mid+1) * sizeof(int));
        int output = net_output(input);
        if(output == initial_output) l = mid + 1;
        else r = mid;
    }
    return l;
}

int main() {
    memset(zeros, 0, sizeof(zeros));
    for(int i = 0; i < maxn; i ++) ones[i] = 1;
    scanf("%d", &T);
    for(int kase = 0; kase < T; kase ++) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i ++) scanf("%d%d", &gate_input[i][0], &gate_input[i][1]);
        if(net_output(zeros) == net_output(ones)) {
            print_repeat(0, n);
            printf("\n");
        }
        else {
            int ans = solve();          //ans is the position where x shuold be placed. it is luckily also the number of 1s that shuold be placed before x.
            print_repeat(1, ans);
            printf("x");
            print_repeat(0, n-1-ans);   //tot number minus 1s and an x.
            printf("\n");
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值