BZOJ3517: 翻硬币

Time Limit: 1 Sec  Memory Limit: 128 MB
Description

有一个n行n列的棋盘,每个格子上都有一个硬币,且n为偶数。每个硬币要么是正面朝上,要么是反面朝上。每次操作你可以选定一个格子(x,y),然后将第x行和第y列的所有硬币都翻面。求将所有硬币都变成同一个面最少需要的操作数。

Input

第一行包含一个正整数n。

接下来n行,每行包含一个长度为n的01字符串,表示棋盘上硬币的状态。

Output 

仅包含一行,为最少需要的操作数。

Sample Input

4
0101
1000
0010
0101

Sample Output

2

HINT

【样例说明】

对(2,3)和(3,1)进行操作,最后全变成1。

【数据规模】

对于100%的数据,n ≤ 1,000。

 


/**************************************************************

    Problem: 3517

    User: ictsing

    Language: C++

    Result: Accepted

    Time:36 ms

    Memory:5244 kb

****************************************************************/

 

//3517: 翻硬币

/*

翻成白的最小值+翻成黑的最小值==n

我我我,,,我看不懂网上的题解

反正我觉得吧,一个位置只有翻一次,或者不翻的可能,

然后啊,这个地方翻,不翻是取决于当前行的抑或,当前列的抑或,以及他本身的。

所以。。。。。。

*/

#include <iostream>  

#include <cstdio>  

using namespace std;  

const int mt = 1000+5;

int a[mt][mt],h[mt],l[mt];  

char ch[mt];  

inline int read()

{

    int num=0,flag=1;

    char ch;

    do{

        ch=getchar();

        if(ch=='-') flag=-1;

    }while(ch<'0'||ch>'9');

    do{

        num=num*10+ch-'0';

        ch=getchar();

    }while(ch>='0'&&ch<='9');

    return num*flag;

}

int main()

{  

    int n=read();

    for(int i=1;i<=n;i++)

     {  

        scanf("%s",ch+1);  

        for(int j=1;j<=n;j++)

        {  

            a[i][j]=ch[j]-'0';  

            h[i]^=a[i][j],l[j]^=a[i][j];  

        }  

    }  

    int ans=0;  

    for(int i=1;i<=n;i++)  

        for(int j=1;j<=n;j++) 

            ans+=h[i]^l[j]^a[i][j];  

    printf("%d\n",min(ans,n*n-ans));  

    return 0;  

}

 


评论(1)

热度(7)