BZOJ1059 / ZJOI2007 矩阵游戏【网络流/二分图】

来源:互联网 发布:淘宝代理商怎么找 编辑:程序博客网 时间:2024/06/08 15:25

Description

小Q很喜欢玩矩阵游戏。矩阵游戏在一个NN黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。帮助小Q写一个程序来判断这些关卡是否有解。

Input

第一行包含一个整数T,表示数据的组数。接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个NN01矩阵(0表示白色,1表示黑色)。

Output

输出文件应包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No

Solution

首先了解以下四个结论:

在同一行的两个数经过变换不会到不同行
在同一列的两个数经过变换不会到不同列

在不同行的两个数经过变换不会到同一行
在不同列的两个数经过变换不会到同一列

(以上结论脑补即可证明)

接下来是一些简单的推导:

由于最终结果是主对角线上全是1,它们符合的条件是“不在同一行”且“不在同一列”,那么可以变换到这种局面的一定也是那n1“不在同一行”且“不在同一列”。

若我们从初始局面中可以找到n1,使得它们“不在同一行”且“不在同一列”,那么一定可以变换为目标局面,否则不可以(见上面四个结论)。

那么题目变成:是否可以找到n个点,他们的x值覆盖了1ny值也覆盖了1n(也就是不同行不同列)。

这样就完全变成了一个简单的二分图匹配,每个黑点(x,y)代表它覆盖了一侧的x和另一侧的y,连边:
xy(a[x][y]=1)

如果这张图有完美匹配,就说明符合了条件。

代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;const int maxn = 100000 + 5;const int INF = (int)1e9;int edge_num = 1, m, n, S, T;int hed[maxn], dep[maxn];struct Edge {    int from, to, nxt, c;} edge[maxn * 4];void addedge(int from, int to, int c){    edge[++edge_num].nxt = hed[from];    edge[edge_num].from = from;    edge[edge_num].to = to;    hed[from] = edge_num;    edge[edge_num].c = c;}void adde(int from, int to, int c){    addedge(from, to, c);    addedge(to, from, 0);}int queue[maxn], head = 0, tail = 0;bool bfs(){    queue[head] = S;    head = tail = 0;    memset(dep, 0, sizeof(dep));    dep[S] = 1;    while (head <= tail){        int cur = queue[head]; head++;        for (int i = hed[cur]; i; i = edge[i].nxt){            int to = edge[i].to;            if (!dep[to] && edge[i].c) {                dep[to] = dep[cur] + 1;                queue[++tail] = to;            }        }    }    return dep[T];}int dfs(int x, int flow){    if (x == T) return flow;    int ret = 0;    for (int i = hed[x]; i; i = edge[i].nxt){        int to = edge[i].to;        if (dep[to] == dep[x] + 1 && edge[i].c){            int tmp = dfs(to, min(flow, edge[i].c));            edge[i].c -= tmp;            edge[i ^ 1].c += tmp;            flow -= tmp;            ret += tmp;        }    }    if (!ret) dep[x] = 0;    return ret;}int dinic(){    int ret = 0;    while (bfs()){        ret += dfs(S, INF);    }    return ret;}void init(){    memset(hed, 0, sizeof hed);    edge_num = 1;}int main(){    int t; scanf("%d", &t);    while(t--){        init();        scanf("%d", &n);        S = 0; T = 2 * n + 1;        for (int i = 1; i <= n; i++)            for (int j = 1; j <= n; j++){            int x;            scanf("%d", &x);            if (x == 1) adde(i, j + n, 1);        }        for (int i = 1; i <= n; i++){            adde(S, i, 1);            adde(i + n, T, 1);        }        puts(dinic() == n ? "Yes" : "No");    }    return 0;}
阅读全文
0 0
原创粉丝点击