給定一個 \(n\times n\) 的 01
矩陣, 每次操做能夠將一行轉置後賦值給某一列, 問最少幾回操做能讓矩陣全爲 1
. 無解輸出 -1
.c++
\(n \le 1000\).spa
首先手玩下樣例就能夠發現一個很是蝦皮的明顯性質: 由於操做是賦值而不是取或, 因而必定是先讓某一行都爲 1
而後用這一行去染全部不是全 1
的列.code
對於構造一個全 1
的行, 若是行號爲 \(k\), 那麼顯然是用某一行的第 \(k\) 列上的 1
去染第 \(k\) 行. 若是初始狀態剛好不存在任何一行的第 \(k\) 列上有 1
, 那麼咱們能夠把任意一個有 1
的行覆蓋到第 \(k\) 列, 那麼就存在某一行的第 \(k\) 列上是 1
了.blog
這個過程當中咱們發現, 只要初始狀態中有 1
就必定有合法方案.get
那麼咱們只要枚舉行號 \(k\) 欽定它來完成染掉全部列的任務, 而後計算出讓它全 1
的最少步數. 若是存在某一行的第 \(k\) 列是 1
那麼答案直接就是第 \(k\) 行 0
的個數, 不然須要一步讓某一行的第 \(k\) 列是 1
, 因而等於 0
的個數 \(+1\).it
而後剩下的就沙雕了, 算一算初始狀態中有多少列不是全 1
就好了.class
因此這題複雜度瓶頸實際上是讀入im
#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\n",ans); } return 0; } } int main(){ rvalue::main(); return 0; }