【HNOI2016模拟4.10】线性代数与逻辑

来源:互联网 发布:qq windows版 编辑:程序博客网 时间:2024/06/05 20:11

题目:

这里写图片描述

题解:

对于读入的A数组的1部分,反转之后变为0,那我们构建的数组B这个位置必须为1,若这个位置是(i,j),则y[i]^y[j]=1。
我们对y进行染色,如果有冲突,则无解.
否则求出每个联通块的两种颜色的点数。
我们要使!B|A的零的个数最多,则使B的1的个数最多,即y中0,1的个数差距最小。
那么可以直接贪心或者背包求出答案。

Code:

#include <cstdio>#include <cstring>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define fd(i, x, y) for(int i = x; i >= y; i --)using namespace std;const int N = 1005;int T, n, a[N][N], bz[N], s[N][2], f[N], g[N], color[N], ans;int final[N], tot;struct node {    int to, next;}e[N * N * 2];void link(int x, int y) {    e[++ tot].next = final[x], e[tot].to = y, final[x] = tot;    e[++ tot].next = final[y], e[tot].to = x, final[y] = tot;}void dg(int x) {    bz[x] = 1;    s[x][0] = 1;    for(int k = final[x]; k; k = e[k].next) {        int y = e[k].to;        if(bz[y] && color[y] == color[x]) {            ans = 0; break;        }        if(bz[y]) continue;        color[y] = !color[x];        dg(y); if(!ans) break;        s[x][0] += s[y][1];        s[x][1] += s[y][0];    }}int main() {    for(scanf("%d", &T); T; T --) {        memset(bz, 0, sizeof bz);        memset(f, 0, sizeof f);        memset(final, 0, sizeof final);        memset(e, 0, sizeof e);        memset(g, 0, sizeof(g));        memset(s, 0, sizeof(s));        tot = 0;        scanf("%d", &n);        int sum = 0;        fo(i, 1, n) fo(j, 1, n) scanf("%d", &a[i][j]);        fo(i, 1, n) fo(j, 1, n) if(a[i][j])            sum ++, link(i, j);        ans = 1;        fo(i, 1, n) if(!bz[i])            g[i] = 1, dg(i);        if(!ans) {            printf("-1\n"); continue;        }        f[0] = 1;        fo(i, 1, n) if(g[i]) {            fd(j, n, 0) {                if(j + s[i][0] <= n) f[j + s[i][0]] |= f[j];                if(j + s[i][1] <= n) f[j + s[i][1]] |= f[j];            }        }        int k = 0;        fd(i, n / 2, 0) {            if(f[i]) {                k = i;                break;            }        }        printf("%d\n", k * (n - k) * 2 - sum);    }}
原创粉丝点击