[BZOJ1059][ZJOI2007]矩阵游戏(二分图匹配)

=== ===

这里放传送门

=== ===

题解

一开始感觉没什么思路然后上来就开始手玩。。玩了一会儿以后发现它每次交换都会导致行和列相互影响这真是太恶心了。。但是也发现黑点之间行和列的相对关系是不会变的,这个意思是说如果这一行有两个黑点,那么肯定不能通过什么变换把这两个点拆到两行去,列也是一样的。
那这个题就变成能不能选出n个点来,让这两个点既不在同一行也不在同一列了。这就是比较常见的模型了,把行列分别放两排点,如果有一个黑点就从对应的行向对应的列连边,那么这就是一个二分图,二分图里的每一条边代表了一个黑点。
因为每行每列只能选一个黑点,那这就是一个二分图的匹配问题。如果最大匹配规模达不到n的话肯定就是无解了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int T,n,p[410],a[100010],nxt[100010],link[410],vis[410],tot,cnt;
void add(int x,int y){
    tot++;a[tot]=y;nxt[tot]=p[x];p[x]=tot;
}
bool find(int u,int k){
    for (int i=p[u];i!=0;i=nxt[i])
      if (vis[a[i]]!=k){
          vis[a[i]]=k;
          if (link[a[i]]==-1||find(link[a[i]],k)){
              link[a[i]]=u;return true;
          }
      }
    return false;
}
int main()
{
    scanf("%d",&T);
    for (int wer=1;wer<=T;wer++){
        scanf("%d",&n);tot=cnt=0;
        memset(p,0,sizeof(p));
        memset(link,-1,sizeof(link));
        for (int i=1;i<=n;i++)
          for (int j=1;j<=n;j++){
              int c;scanf("%d",&c);
              if (c==1){add(i,j+n);add(j+n,i);}
          }
        for (int i=1;i<=2*n;i++){
            vis[i]=i;
            if (find(i,i)) ++cnt;
        }
        if (cnt==2*n) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值