• BZOJ1059 [ZJOI2007]矩阵游戏 二分图匹配 匈牙利算法


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1059


    题意概括

      有一个n*n(n<=200)的01矩阵,问你是否可以通过交换整行和整列使得左上角到右下角的对角线上的数字都是1。


    题解

      我们发现,题目模型可以转换。

      其实题目就是叫我们求是否存在一些1,这些1所在的行和列互不相同。

      我给一个小小的证明:

      假设我们选出了一个n个点的坐标。

      如果这n个点所在的行、列互不相同,那么,我们一定可以通过交换来完成任务。

      比如:依次把每一行的1通过列交换交换到相应位置。

      如果这n个点所在的行有重复,那么,无论如何,位于同一行的两个点是不可能弄到两个不同的行上的。所以一定不行。

      列有重复也同理。

      那么就成了一个行和列的匹配问题。

      转化成二分图匹配,匈牙利算法跑一跑就过去了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    using namespace std;
    const int N=200+5;
    vector <int> e[N];
    int T,n,match[N*2];
    bool vis[N*2];
    bool dfs(int x){
        for (int i=0,y;i<e[x].size();i++)
            if (!vis[y=e[x][i]]){
                vis[y]=1;
                if (match[y]==-1||dfs(match[y])){
                    match[y]=x;
                    return 1;
                }
            }
        return 0;
    }
    int main(){
        scanf("%d",&T);
        while (T--){
            scanf("%d",&n);
            for (int i=1;i<=n;i++)
                e[i].clear();
            for (int i=1;i<=n;i++)
                for (int j=1,x;j<=n;j++){
                    scanf("%d",&x);
                    if (x)
                        e[i].push_back(j+n);
                }
            memset(match,-1,sizeof match);
            int cnt=0;
            for (int i=1;i<=n;i++){
                memset(vis,0,sizeof vis);
                if (dfs(i))
                    cnt++;
            }
            puts(cnt==n?"Yes":"No");
        }
        return 0;
    }
  • 相关阅读:
    javascript执行上下文
    javascript深浅拷贝
    javascript模块化
    javascript类型转换
    闭包
    通过插槽分发内容
    组件上使用v-model
    Vue $emit $event 传值(子to父)
    Vue Prop属性(父to子)
    Vue组件全局/局部注册
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1059.html
Copyright © 2020-2023  润新知