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

        怎么说,先引用一下别人的博客吧!(我觉得它很好地反映了我看到这道题后的思路)

    的确,如果只判断每一行,每一列是否都至少有一个1,行和每一列都至少有一个1,会WA掉的。后来无奈之下看了题解,是二分图匹配,(然而蒟蒻还不懂,去请教了一下czl,经过教导之后终于懂了)。大致是这样的吧!

    如果 X 行 Y 列 有一个 黑格子 ,就在 x 和 y 之间连边(x是指行,y是指列,两者是在二分图的两边的), 然后,我们可以把变换看作交换 X 中的点(不改变它们连边的情况,简单地说,比如交换A和B,如果之前A有一条边连向C,那么交换后A仍有一条边连向C), 使得最后每一个xi 都有一条边连向 y, 这其实就是一个二分图最大匹配的问题。 加油,多学多思考。看了其他人一些有关二分图的题,大多都体现出了一个一一对应的关系,在这里,一一对应的关系可以表现为 如果一开始的两个格子在同一行,那么它们之间就将始终在同一行,那么它们之间就这能有一个去填充这一行的主对角线, 即每一行中只能有一个去填充主对角线。 同理,列也是一样的。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<vector>
      5 #include<queue>
      6 #define clr(x,y) memset(x,y,sizeof(x))
      7 #define rep(i,j,k) for(int i = j; i <= k; i++)
      8 #define maxn 205
      9 using namespace std;
     10  
     11 int read()
     12 {
     13     int s = 0, t =1; char c = getchar();
     14     while( !isdigit(c) ){
     15         if( c == '-' ) t = -1; c = getchar();
     16     }
     17     while( isdigit(c) ){
     18         s = s * 10 + c -'0'; c = getchar();
     19     }
     20     return s * t;
     21 }
     22  
     23 int mx[maxn], my[maxn], dx[maxn], dy[maxn], n1, n2;
     24 vector<int> G[maxn]; 
     25 queue<int> q;
     26 bool vis[maxn];
     27  
     28 void clear()
     29 {
     30     while( !q.empty() ) q.pop();
     31     rep(i,0,maxn-1){
     32         G[i].clear();
     33     }
     34 }
     35  
     36 bool match(int x)
     37 {
     38     int s = G[x].size();
     39     rep(i,0,s-1){
     40         int to = G[x][i];
     41         if( !vis[to] && dy[to] == dx[x] + 1 ){
     42             vis[to] = 1;
     43             if( !my[to] || match(my[to]) ){
     44                 my[to] = x; mx[x] =  to;
     45                 return 1;
     46             }
     47         }
     48     }
     49     return 0;
     50 }
     51  
     52 int matching(){
     53     clr(mx,0); clr(my,0);
     54     int ans = 0;
     55     while( true ){
     56         bool flag = 0;
     57         while( !q.empty() ) q.pop();
     58         clr(dx,0); clr(dy,0);
     59         rep(i,1,n1) if( !mx[i] ) q.push(i);
     60         while( !q.empty() ){
     61             int u = q.front(); q.pop();
     62             int s = G[u].size();
     63             rep(i,0,s-1){
     64                 int to = G[u][i];
     65                 if( !dy[to] ) {
     66                     dy[to] = dx[u] + 1;
     67                     if( my[to] ) {
     68                         dx[my[to]] = dy[to] + 1;
     69                         q.push(my[to]);
     70                     } else flag = 1;
     71                 } 
     72             }
     73         }
     74         if( !flag ) break;
     75         clr(vis,0); 
     76         rep(i,1,n1){
     77             if( !mx[i] && match(i) ) ans++; 
     78         }
     79     }
     80     return ans;
     81 }
     82  
     83  
     84 int main()
     85 {
     86     int t = read();
     87     while( t-- ){
     88         clear();
     89         n1 = read(); 
     90         rep(i,1,n1){
     91             rep(j,1,n1){
     92                 if( read() ){
     93                     G[i].push_back(j);
     94                 }
     95             }
     96         }
     97         if( matching() == n1 ) puts("Yes");
     98         else puts("No");
     99     }
    100     return 0;
    101 }
  • 相关阅读:
    Linux服务下,设置开机自启动服务
    [知识分享] 实用且具有参考意义的博客网站
    [AutoHotKey] 自定义配置快捷键
    [driver] probe调用的时机
    [vscode] 常用快捷键
    [Linux] 双系统下linux自动挂载windows下的逻辑分区
    [Linux] manjaro中文输入法配置
    [Linux] gnome桌面顶栏透明效果
    [Linux] manjaro窗口按钮异常
    博客园简约主题设置
  • 原文地址:https://www.cnblogs.com/83131yyl/p/5098710.html
Copyright © 2011-2022 走看看