棋盘变幻

Description

小G在一个n*m的棋盘上随意放上了一些黑色的棋子,然后又在剩下所有没有放棋子的格子里放上了白色的棋子。现在小G想知道他是否能通过以下两种变换将整个棋盘上的棋子全部变成白色。
变幻1:选择一列,将这一列的棋子全部反色,即黑变白,白变黑。
变幻2:选择一行,将这一行的棋子全部反色。
如果能将整个棋盘上的棋子全部变成白色,则输出最少需要的变幻次数。否则输出经过若干次变幻后,棋盘上最少的黑子个数。

Input

第一行两个正整数n,m,含义见题面。
接下里n行,每行m个字符,‘0’表示白子,‘1’表示黑子。

Output

一行一个整数ans,含义见题面。

Solution

$2^n$ 枚举每一列是否翻转。之后每一行是独立的,单独判断是否要翻转。$sum$ 统计此列的黑子数量,$mn$ 统计剩余黑子数。如果黑子多,就要翻转,然后累计翻不了的棋子。如果可以全部翻完,记下最小步数。

时间复杂度:$O(2^n*m)$

 1 //chess 
 2 #include<bits/stdc++.h>
 3 #define int long long
 4 using namespace std;
 5 const int N=30,inf=1e18;
 6 int n,m,a[N][N],mn,sum,x=inf,y,ans=inf;
 7 char s[N][N];
 8 void solve(int i){
 9     for(int j=1;j<=n;j++)
10         if(i>>(j-1)&1){for(int k=1;k<=m;k++) a[j][k]=abs(a[j][k]-1);y++;}
11 }
12 signed main(){
13     freopen("chess.in","r",stdin);
14     freopen("chess.out","w",stdout);
15     scanf("%lld%lld",&n,&m);
16     for(int i=1;i<=n;i++)
17         scanf("%s",s[i]+1);
18     for(int i=1;i<=n;i++) 
19         for(int j=1;j<=m;j++)
20             a[i][j]=s[i][j]-'0';
21     for(int i=0;i<(1<<n);i++){
22         y=0,solve(i),mn=0;
23         for(int j=1;j<=m;j++){
24             sum=0;
25             for(int k=1;k<=n;k++) sum+=a[k][j];
26             if(sum>n-sum) y++,mn+=(n-sum);
27             else mn+=sum;
28         }
29         if(mn==0) x=min(x,y);
30         else ans=min(ans,mn);
31         solve(i);
32     }
33     if(x!=inf) printf("%lld\n",x);
34     else printf("%lld\n",ans);
35     return 0;
36 }

 

猜你喜欢

转载自www.cnblogs.com/mao1t/p/chess.html