[BZOJ]1059 矩阵游戏(ZJOI2007)

  虽然说是一道水题,但小C觉得还是挺有意思的,所以在这里mark一下。

Description

  小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。

Input

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

Output

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

Sample Input

  2
  2
  0 0
  0 1
  3
  0 0 1
  0 1 0
  1 0 0

Sample Output

  No
  Yes

HINT

  对于100%的数据,N ≤ 200。

Solution

  拿到这道题目肯定要思考,什么样的局面通过交换行列可以变成主对角线上都为黑格的情况?

  由于交换是可逆的,我们倒过来思考,主对角线上都是黑格的情况通过交换行列可以变成什么局面。

  这样就一目了然了。一开始是1~n的排列,每次交换行列相当于交换两个位置上的数字。

  这样问题就转化成:是否能从每行选出恰好一个黑格,n行黑格代表的列数正好组成一个1~n的全排列。

  正解是二分图匹配。全排列可以看作是行和列的匹配,思路很清晰。时间复杂度O(n^2)(匈牙利算法)/O(n^1.5)(网络流)。

  但是小C这里要介绍的,是另一种做法。

  想到矩阵和排列,我们会很自然地想起行列式。

  我们思考一下行列式的计算公式:

  发现如果一个排列上的所有数都不为0,就一定会对答案有贡献!

  所以我们就直接求这个矩阵的行列式的值就可以了???复杂度O(n^3)。

  当然不行,这些排列对答案的贡献有正有负,矩阵的值全为0或1的话很容易凑出0。例如{{0,1,1},{0,1,1},{1,0,0}}。

  那怎么办?

  很简单啊,我们给矩阵里的黑格都随机一个权值就好了嘛。

  什么?还是WA?

  我们来看一看行列式等于0还有什么条件:

    1.有一行或一列全为0的情况;
    2.有两行或两列数值成比例的情况;
    3.行向量之间或列向量之间有相关的情况;
    4.逆矩阵不存在的情况:
    5.行列式对应的矩阵的秩小于行列式的阶数的情况……

  够了!似乎第二条看起来特别扎眼,于是我们给矩阵里的黑格都随机一个质数权值如何?

  过了卧槽。

  二分图匹配:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MN 205
using namespace std;
bool u[MN],mp[MN][MN];
int mat[2][MN];
int t,n;

inline int read()
{
    int n=0,f=1; char c=getchar();
    while (c<‘0‘ || c>‘9‘) {if(c==‘-‘)f=-1; c=getchar();}
    while (c>=‘0‘ && c<=‘9‘) {n=n*10+c-‘0‘; c=getchar();}
    return n*f;
}

bool dfs(int x)
{
    if (u[x]) return false;
    u[x]=true;
    for (register int i=1;i<=n;++i)
    {
        if (!mp[x][i]||mat[0][x]==i) continue;
        if (!mat[1][i]||dfs(mat[1][i])) {mat[0][x]=i; mat[1][i]=x; return true;}
    }
    return false;
}

int main()
{
    register int i,j;
    t=read();
    while (t--)
    {
        n=read();
        for (i=1;i<=n;++i)
            for (j=1;j<=n;++j) mp[i][j]=read();
        memset(mat,0,sizeof(mat));
        for (i=1;i<=n;++i)
        {
            memset(u,0,sizeof(u));
            if (!dfs(i)) break;
        }
        if (i<=n) puts("No"); else puts("Yes");
    }
}

  高斯消元求行列式:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define mod 1000000007
#define MP 2000005
#define MN 205
using namespace std;
int a[MN][MN],p[MP];
bool u[MP];
int t,n,pin;

inline int read()
{
    int n=0,f=1; char c=getchar();
    while (c<‘0‘ || c>‘9‘) {if(c==‘-‘)f=-1; c=getchar();}
    while (c>=‘0‘ && c<=‘9‘) {n=n*10+c-‘0‘; c=getchar();}
    return n*f;
}

int mi(int x,int y)
{
    register int z=1;
    for (;y;x=1LL*x*x%mod,y>>=1) if (y&1) z=1LL*z*x%mod;
    return z;
}

void init()
{
    register int i,j;
    for (i=2;i<MP;++i)
    {
        if (!u[i]) p[++pin]=i;
        for (j=1;i*p[j]<MP;++j)
        {
            u[i*p[j]]=true;
            if (i%p[j]==0) break;
        }
    }
}

int main()
{
    register int i,j,k,x,mxi,lt;
    srand(9875321); init();
    t=read();
    while (t--)
    {
        n=read();
        for (i=1;i<=n;++i)
            for (j=1;j<=n;++j)
                if (read()&1) a[i][j]=p[(rand()*rand()%pin+rand())%pin+1];
                else a[i][j]=0;
        for (i=1;i<n;++i)
        {
            mxi=i;
            for (j=i+1;j<=n;++j) if (a[j][i]>a[mxi][i]) mxi=j;
            if (mxi!=i) swap(a[mxi],a[i]);
            if (!a[i][i]) break;
            for (j=i+1;j<=n;++j)
                for (lt=1LL*mi(a[i][i],mod-2)*a[j][i]%mod,k=i;k<=n;++k)
                    a[j][k]=(a[j][k]-1LL*a[i][k]*lt%mod+mod)%mod;
        }
        if (i<n||!a[n][n]) puts("No"); else puts("Yes");
    }
}

Last Word

  行列式还能这么用.jpg。

  这题又让小C了解了一下行列式的一点点性质,好像还练习了一下乱搞技巧?

  小C的n^3做法似乎成功拿到了bzoj那一题的垫底:

时间: 2024-10-05 04:40:52

[BZOJ]1059 矩阵游戏(ZJOI2007)的相关文章

BZOJ 1059 矩阵游戏(神奇的二分图匹配)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1059 题意:给出一个N*N的01矩阵.有两种操作:(1)交换任意两行:(2)交换任意两列.问最后能否使得主对角线上全部为1? 思路:我们发现,对于同一行的两个1,比如 (i,j)和(i,j+1),无论如何我们也不能把这两个1都移动到主对角线上,换句话说,最多能够将其中一个1移动到主对角线上.因为,若我们想将这两 个同时移动到主对角线上,不妨设为(i1,i1),(i2,i2).首先,我们

bzoj 1059 矩阵游戏

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1059 题解: 很玄学的问题…… 因为不同行或者不同列的格子,交换仍然不同行或者不同列 所以把问题转化为从黑格子里选n个,它们的横纵坐标都不相同 然后二分图匹配……两个子集分别是横坐标和纵坐标,如果求出的最大匹配为n,则成立,否则不成立 1 #include<cstdio> 2 #include<cstring> 3 #define MAXN 410 4 int n,cnt,

洛谷 P1129 BZOJ 1059 cogs 660 [ZJOI2007]矩阵游戏

题目描述 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作: 行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色) 列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色) 游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色. 对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!

矩阵游戏|ZJOI2007|BZOJ1059|codevs1433|luoguP1129|二分图匹配|匈牙利算法|Elena

1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MB Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏--矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择 矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换 对应格子的颜色)游戏的目标,即通过若干次操作,

BZOJ 3240 矩阵游戏

矩阵不要乱用欧拉定理.... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000007 #define maxn 1000050 using namespace std; char n[maxn],m[maxn]; long long n1,n2,m1,m2,k,k1,k2,a,b,c,d,ans; long long f_

【BZOJ】【1059】【ZJOI2007】矩阵游戏

二分图完美匹配/匈牙利算法 如果a[i][j]为黑点,我们就连边 i->j ,然后跑二分图最大匹配,看是否有完美匹配. <_<我们先考虑行变换:对于第 i 行,如果它第 j 位是黑点,那么我们一定可以通过交换行来将这一行放到新矩阵的第 j 行,使a[j][j]这一位满足题目要求:同时,第 j 行也必须有一个原矩阵的行放过来,这样,就满足一一对应的关系,所以就是[匹配]了…… 然而列变换:我们交换两列a和b,只是相当于将原来从左部连到右部的 a 点的边,与从左部连到右部的 b 点的边交换了

bzoj 1059: [ZJOI2007]矩阵游戏 二分图匹配

1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1891  Solved: 919[Submit][Status] Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵

bzoj 1059: [ZJOI2007]矩阵游戏 [二分图][二分图最大匹配]

Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N *N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择 矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换 对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑 色.对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根

1059: [ZJOI2007]矩阵游戏

1059: [ZJOI2007]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2154  Solved: 1053[Submit][Status] Description 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏.矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的).每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩