• [LOJ 6030]「雅礼集训 2017 Day1」矩阵


    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵

    题意

    给定一个 (n imes n)01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解输出 -1.

    (n le 1000).

    题解

    首先手玩下样例就可以发现一个非常虾皮的明显性质: 因为操作是赋值而不是取或, 于是一定是先让某一行都为 1 然后用这一行去染所有不是全 1 的列.

    对于构造一个全 1 的行, 如果行号为 (k), 那么显然是用某一行的第 (k) 列上的 1 去染第 (k) 行. 如果初始状态恰好不存在任何一行的第 (k) 列上有 1, 那么我们可以把任意一个有 1 的行覆盖到第 (k) 列, 那么就存在某一行的第 (k) 列上是 1 了.

    这个过程中我们发现, 只要初始状态中有 1 就一定有合法方案.

    那么我们只要枚举行号 (k) 钦定它来完成染掉所有列的任务, 然后计算出让它全 1 的最少步数. 如果存在某一行的第 (k) 列是 1 那么答案直接就是第 (k)0 的个数, 否则需要一步让某一行的第 (k) 列是 1, 于是等于 0 的个数 (+1).

    然后剩下的就沙雕了, 算一算初始状态中有多少列不是全 1 就行了.

    所以这题复杂度瓶颈其实是读入

    参考代码

    #include <bits/stdc++.h>
    
    namespace rvalue{
    	const int MAXN=1010;
    
    	int n;
    	int cntx[MAXN];
    	int cnty[MAXN];
    	char a[MAXN][MAXN];
    
    	int main(){
    		scanf("%d",&n);
    		bool valid=false;
    		for(int i=1;i<=n;i++){
    			scanf("%s",a[i]+1);
    			for(int j=1;j<=n;j++){
    				if(a[i][j]=='#'){
    					valid=true;
    					++cntx[i];
    					++cnty[j];
    				}
    			}
    		}
    		if(!valid)
    			puts("-1");
    		else{
    			int ans=n;
    			for(int i=1;i<=n;i++)
    				if(cnty[i])
    					ans=std::min(ans,n-cntx[i]);
    				else
    					ans=std::min(ans,n-cntx[i]+1);
    			for(int i=1;i<=n;i++)
    				if(cnty[i]!=n)
    					++ans;
    			printf("%d
    ",ans);
    		}
    		return 0;
    	}
    }
    
    int main(){
    	rvalue::main();
    	return 0;
    }
    
    

  • 相关阅读:
    系统数据库如何恢复Master数据库
    在Orderby子句中使用CASE 语句
    SQL NOTECURSOR
    MVC 中静态文件部分动态化
    SQL NOTCTE
    Get data style from Excel
    SQL NOTPARTITION
    LAMDA表达式学习
    SQL NOTEVARIABLE
    起II6.0中使用windows2003自带的虚拟主机管理系统
  • 原文地址:https://www.cnblogs.com/rvalue/p/10603044.html
Copyright © 2020-2023  润新知