zoukankan      html  css  js  c++  java
  • bzoj2466

    高斯消元+搜索

    很明显每个开关只能按一次,那么我们可以想到高斯消元,其实就是解异或方程组,但是最后会有一些自由元,也就是有x+y=z,x+y=z这种一样的方程就会产生自由元,那么我们爆搜自由元取值,每次把自由元回带入方程,因为形如x+y=z这样的方程就需要回带,然后就解出一组解,取最小值即可。这当然不是正解,100怎么能爆搜,正解是树形dp。

    #include<bits/stdc++.h>
    using namespace std;
    const int Maxlen = 10000010, N = 110;
    int n, ans;
    int a[N][N], mark[N], val[N];
    namespace IO 
    {
        char buf[Maxlen], *C = buf;
        int Len;
        inline void read_in()
        {
            Len = fread(C, 1, Maxlen, stdin);
            buf[Len] = '';
        }
        inline void fread(int &x) 
        {
            x = 0;
            int f = 1;
            while (*C < '0' || '9' < *C) { if(*C == '-') f = -1; ++C; }
            while ('0' <= *C && *C <= '9') x = (x << 1) + (x << 3) + *C - '0', ++C;
            x *= f;
        }
        inline void read(int &x)
        {
            x = 0;
            int f = 1; char c = getchar();
            while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
            while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + c - '0'; c = getchar(); }
            x *= f;
        }
    } using namespace IO;
    void dfs(int d, int tot)
    {
        if(tot >= ans) return;
        if(d == 0)
        {
            ans = min(ans, tot);
            return;
        }
        if(mark[d])
        {
            int x = a[d][n + 1];
            for(int i = 1; i <= n; ++i) if(!mark[i] && a[d][i]) x ^= val[i];
            dfs(d - 1, tot + x);
        }
        else
        {
            val[d] = 0;
            dfs(d - 1, tot);
            val[d] = 1;
            dfs(d - 1, tot + 1);
        }
    }
    void gauss()
    {
        ans = n;
        for(int now = 1; now <= n; ++now)
        {
            int pos = now;
            while(!a[pos][now] && pos <= n) ++pos;
            if(pos == n + 1) continue;
            swap(a[pos], a[now]);
            for(int i = 1; i <= n; ++i) if(a[i][now] && i != now)
                for(int j = 1; j <= n + 1; ++j) a[i][j] ^= a[now][j];
            mark[now] = 1;
        }
        dfs(n, 0);
        printf("%d
    ", ans);
    }
    int main()
    {
        while(1)
        {
            read(n);
            if(n == 0) break;
            memset(val, 0, sizeof(val));
            memset(a, 0, sizeof(a));
            memset(mark, 0, sizeof(mark));
            for(int i = 1; i <= n; ++i) 
            {
                a[i][i] = 1;
                a[i][n + 1] = 1;
            }
            for(int i = 1; i < n; ++i)
            {
                int u, v;
                read(u);
                read(v);
                a[u][v] = a[v][u] = 1;
            }
            gauss();
        }
        return 0;
    }
    
    View Code
  • 相关阅读:
    解压缩编码列表
    按既定顺序创建目标数组
    整数的各位积和之差
    好数对的数目
    拿硬币
    设计 Goal 解析器
    【求助】win 2008 R2 远程桌面多用户,破解最大连接数2的限制
    Java 字符串拼接 五种方法的性能比较分析 从执行100次到90万次
    Java abstract class 和 interface 的区别
    忘记BIOS超级管理员密码,怎么破解?
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7414083.html
Copyright © 2011-2022 走看看