zoukankan      html  css  js  c++  java
  • 洛谷 P1129 [ZJOI2007]矩阵游戏 解题报告

    P1129 [ZJOI2007]矩阵游戏

    题目描述

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

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

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

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

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

    输入输出格式

    输入格式:

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

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

    输出格式:

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

    说明

    对于(20)%的数据,(N ≤ 7)

    对于(50)%的数据,(N ≤ 50)

    对于(100)%的数据,(N ≤ 200)


    研究一下操作和要求,我们可以这么转化:每行至少有一个(1)并且这些(1)互相不在同一列

    对于行(i),我们用了坐标((i,j))(1),那么第(j)列的(1)不就废了吗?

    好的,求匹配。

    坐标为((i,j))的点作为第(i)行第(j)列的边。

    求每一行和每一列的最大匹配数即可。

    二分图匹配。


    code:

    #include <cstdio>
    #include <cstring>
    const int N=202;
    struct Edge
    {
        int to,next;
    }g[N*N];
    int T,head[N],cnt=0,n;
    
    void add(int u,int v)
    {
        g[++cnt].to=v,g[cnt].next=head[u],head[u]=cnt;
    }
    int match[N],used[N];
    bool m_match(int now)
    {
        for(int i=head[now];i;i=g[i].next)
        {
            int v=g[i].to;
            if(!used[v])
            {
                used[v]=1;
                if(!match[v]||m_match(match[v]))
                {
                    match[v]=now;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
        scanf("%d",&T);
        int is;
        while(T--)
        {
            memset(match,0,sizeof(match));
            memset(head,0,sizeof(head));
            scanf("%d",&n);cnt=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                {
                    scanf("%d",&is);
                    if(is) add(i,j);
                }
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                memset(used,0,sizeof(used));
                if(m_match(i)) ans++;
            }
            if(ans==n) printf("Yes
    ");
            else printf("No
    ");
        }
    }
    
    

    我的一些出现的细节错误:

    1. 匈牙利used数组置true时机(似乎经常错)
    2. used置0的时机(在if的外面)
    3. 前向星head,cnt置0

    2018.5.5

  • 相关阅读:
    C# 获取文件的修改时间、访问时间、创建时间
    Nhibernate Or多条件查询
    C# 将GridView当前页数据导成Execl
    C# 清空文件夹
    TreeView默认收缩
    JS控制控件的隐藏显示
    div置顶,不随滚动条滚动而滚动
    js 父窗体与子窗体的调用
    树形菜单的绑定以及链接
    2010.10.16 OA项目组一周报告 CQ
  • 原文地址:https://www.cnblogs.com/butterflydew/p/8996087.html
Copyright © 2011-2022 走看看