zoukankan      html  css  js  c++  java
  • 矩阵游戏[ZJOI2007]

                                题目传送门     

    题目描述

    小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏。矩阵游戏在一个N*N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。每次可以对该矩阵进行两种操作:

    行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)

    列交换操作:选择矩阵的任意两列,交换这两列(即交换对应格子的颜色)

    游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。

    对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。

    输入输出格式

    输入格式:

    第一行包含一个整数T,表示数据的组数。

    接下来包含T组数据,每组数据第一行为一个整数N,表示方阵的大小;接下来N行为一个N*N的01矩阵(0表示白色,1表示黑色)。

    输出格式:

    包含T行。对于每一组数据,如果该关卡有解,输出一行Yes;否则输出一行No。

    输入输出样例

    输入样例#1: 
    2
    2
    0 0
    0 1
    3
    0 0 1
    0 1 0
    1 0 0
    
    输出样例#1: 
    No
    Yes
    

    说明

    对于20%的数据,N ≤ 7

    对于50%的数据,N ≤ 50

    对于100%的数据,N ≤ 200

           

     题解:

           一道不太好建模的二分图...

      首先我们可以发现直接把格子当做点是不可做的。所以我们考虑把每一列当做一个点,把每一行当做一个点。考虑末状态,可以看做第i行向第i列连了一条匹配边。行交换操作可以看做匹配边的交换。

      比如(1,4)、(2,3)是黑格子的话可以看做1->4,2->3连了匹配边(注意,箭头左右分属不同集合,即使数值相同,代表的含义也不同,在代码中的编号也是不同的)。那么交换第一第二行后黑格子就变成了(1,3)、(2,4),匹配边为1->3,2->4。可以发现交换x,y两行就是交换x,y的匹配边。交换列同理。

      所以我们可以得出的一个结论就是如果想要达到最终状态,那么一开始最大匹配数就要等于n.

      可以用网络流求最大匹配数。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #define LL long long
     7 #define RI register int
     8 using namespace std;
     9 const int INF = 0x7ffffff ;
    10 const int N = 200 + 10 ;
    11 const int M = 1e7 + 10 ;
    12 
    13 inline int read() {
    14     int k = 0 , f = 1 ; char c = getchar() ;
    15     for( ; !isdigit(c) ; c = getchar())
    16       if(c == '-') f = -1 ;
    17     for( ; isdigit(c) ; c = getchar())
    18       k = k*10 + c-'0' ;
    19     return k*f ;
    20 }
    21 struct Edge {
    22     int to, next, flow ;
    23 }e[M] ;
    24 int n, s, t, ansf, cnt = 1 ; int head[N<<1], dep[N<<1] ;
    25 inline void add_edge(int x,int y,int ff) {
    26     e[++cnt].to = y, e[cnt].next = head[x], head[x] = cnt, e[cnt].flow = ff ;
    27     e[++cnt].to = x, e[cnt].next = head[y], head[y] = cnt, e[cnt].flow = 0 ;
    28 }
    29 
    30 inline bool F_bfs() {
    31     memset(dep,0,sizeof(dep)) ;
    32     queue<int>q ; q.push(s) ; dep[s] = 1 ;
    33     while(!q.empty()) {
    34         int x = q.front() ; q.pop() ;
    35         for(int i=head[x];i;i=e[i].next) {
    36             int y = e[i].to ; if(dep[y] || !e[i].flow) continue ;
    37             dep[y] = dep[x]+1 ; q.push(y) ;
    38         }
    39     }
    40     return dep[t] ;
    41 }
    42 int F_dfs(int x,int minflow) {
    43     if(x == t || !minflow) return minflow ;
    44     int fflow = 0 ;
    45     for(int i=head[x];i;i=e[i].next) {
    46         int y = e[i].to ; if(dep[y] != dep[x]+1 || !e[i].flow) continue ;
    47         int temp = F_dfs(y,min(minflow,e[i].flow)) ;
    48         fflow += temp, minflow -= temp ;
    49         e[i].flow -= temp, e[i^1].flow += temp ;
    50         if(!minflow) break ;
    51     }
    52     return fflow ;
    53 }
    54 
    55 
    56 inline void solve() {
    57     n = read() ; memset(head,0,sizeof(head)) ; ansf = 0 ; s = (n<<1)+1, t = s+1 ;
    58     for(int i=1;i<=n;i++) {
    59         add_edge(s,i,1) ; add_edge(i+n,t,1) ;
    60         for(int j=1;j<=n;j++) {
    61             bool x = read() ;
    62             if(x) {
    63                 add_edge(i,j+n,1) ;
    64             }
    65         }
    66     }
    67     while(F_bfs()) ansf += F_dfs(s,INF) ;
    68     if(ansf == n) printf("Yes
    ") ; else printf("No
    ") ;
    69 }
    70 
    71 int main() {
    72     int t = read() ;
    73     while(t--) solve() ;
    74     return 0 ;
    75 }
  • 相关阅读:
    NETCore中RabbitMQ的使用
    net core 中间件
    表达式和表达式树
    NET
    解决Net内存泄露原因
    Spring的IoC容器-Spring BeanFactory容器
    Spring的Hello World工程
    Linux下使用curl进行http请求(转)
    Java教程收集
    使用wget进行整站下载(转)
  • 原文地址:https://www.cnblogs.com/zub23333/p/8796578.html
Copyright © 2011-2022 走看看