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;
}

 

转载于:https://www.cnblogs.com/zhouzhendong/p/BZOJ1059.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值