zoukankan      html  css  js  c++  java
  • BZOJ1059 [ZJOI2007]矩阵游戏 二分图匹配

    1059: [ZJOI2007]矩阵游戏

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 6162  Solved: 2999
    [Submit][Status][Discuss]

    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
    【数据规模】
    对于100%的数据,N ≤ 200

     

    一直在想办法dfs+剪枝,后来看了眼BZOJ的一句话题解才意识到是个裸的二分图匹配,行列的最大匹配等于n输出yes,否则输出no

    /**************************************************************
        Problem: 1059
        User: mizersy
        Language: C++
        Result: Accepted
        Time:360 ms
        Memory:2308 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN = 510;
    int uN,vN;
    int g[MAXN][MAXN];
    int linker[MAXN];
    bool used[MAXN];
    bool dfs(int u)
    {
        for(int v = 0; v < vN; v++)
            if(g[u][v] && !used[v])
            {
                used[v] = true;
                if(linker[v] == - 1 || dfs(linker[v]))
                {
                    linker[v] = u;
                    return true;
                }
            }
        return false;
    }
    int hungary()
    {
        int res = 0;
        memset(linker, - 1,sizeof(linker));
        for(int u = 0; u < uN; u++)
        {
            memset(used,false,sizeof(used));
            if(dfs(u))
                res++;
        }
        return res;
    }
     
    int T,n;
    int main(){
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            uN = vN = n;
            for (int i = 0;i < n;++i)
            {
                for (int j = 0;j < n;++j)
                {
                    scanf("%d",&g[i][j]);
                }
            }
            int ans = hungary();
            if (ans < n) puts("No");else puts("Yes");
        }
    }

    下面是dfs的错误代码:

    /**************************************************************
        Problem: 1059
        User: mizersy
        Language: C++
        Result: Time_Limit_Exceed
    ****************************************************************/
     
    #include <bits/stdc++.h>
    using namespace std;
    int T,n;
    int a[205][205];
    bool r[205],c[205];
    int numr,numc;
    bool vis[205];
    struct Node{
        int r,c;
    };
    bool flag;
    vector <Node> G;
     
    void dfs(int x,int pos,int num)
    {
        if (flag) return;
        if (num == n) {
            flag = true;
            return;
        }
        for (int i = r[x+1];i < G.size();++i)
        {
            Node p = G[i];
            if (p.r > x+1) return;
            if (!vis[p.c]){
                vis[p.c] = 1;
                dfs(p.r,i,num+1);
                vis[p.c] = 0;
            }
        }
    }
     
    int main(){
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            flag = false;
            memset(vis,0,sizeof(vis));
            G.clear();
            memset(r,0,sizeof(r));
            memset(c,0,sizeof(c));
            numr = numc = 0;
            for (int i = 1;i <= n;++i)
            {
                for (int j = 1;j <= n;++j)
                {
                    scanf("%d",&a[i][j]);
                    if (a[i][j] == 1 && !r[i]) r[i] = max((int)G.size(),1),++numr;
                    if (a[i][j] == 1 && !c[j]) c[j] = 1,++numc;
                    if (a[i][j]) G.push_back(Node{i,j});
                }
            }
            if (numr != n || numc != n)
            {
                puts("No");
                continue;
            }
            for (int i = 0;i < G.size();++i)
            {
                if (flag) break;
                Node p = G[i];
                if (p.r > 1) break;
                vis[p.c] = 1;
                dfs(p.r,i,1);
                vis[p.c] = 0;
            }
            if (flag) puts("Yes"); else puts("No");
        }
    }
    View Code
  • 相关阅读:
    poj 1789 每个字符串不同的字母数代表两个结点间的权值 (MST)
    poj 1251 poj 1258 hdu 1863 poj 1287 poj 2421 hdu 1233 最小生成树模板题
    poj 1631 最多能有多少条不交叉的线 最大非降子序列 (LIS)
    hdu 5256 最少修改多少个数 能使原数列严格递增 (LIS)
    hdu 1025 上面n个点与下面n个点对应连线 求最多能连有多少条不相交的线 (LIS)
    Gym 100512F Funny Game (博弈+数论)
    UVa 12714 Two Points Revisited (水题,计算几何)
    UVa 12717 Fiasco (BFS模拟)
    UVa 12718 Dromicpalin Substrings (暴力)
    UVa 12716 && UVaLive 6657 GCD XOR (数论)
  • 原文地址:https://www.cnblogs.com/mizersy/p/9523983.html
Copyright © 2011-2022 走看看