问题描述

UVA11464


题解

第一直觉爆搜。

发现 \(N \le 15\) ,然后后面每行都可以通过第一行递推出来。

爆搜第一行,递推后面+check


\(\mathrm{Code}\)

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') ch=getchar(),fh=-1;
    else fh=1;
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=fh;
}

const int maxn=17;
const int INF=0x3f3f3f3f;

int T,cas;

int n;
int a[maxn][maxn],b[maxn][maxn];

int ans;

int calc(){
    int res=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(a[i][j]==1&&b[i][j]==0) ++res;
        }
    }
    return res;
}

bool check(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int k=a[i][j-1]+a[i][j+1]+a[i-1][j]+a[i+1][j];
            if(k&1) return false;
        }
    }
    return true;
}

void rebuild(){
    for(int i=2;i<=n;i++){
        for(int j=1;j<=n;j++) a[i][j]=b[i][j];
    }
}

void dp(){
    for(int i=2;i<=n;i++){
        for(int j=1;j<=n;j++){
            int k=a[i-1][j-1]+a[i-1][j+1]+a[i-2][j];
            if(k&1) a[i][j]=1;
        }
    }
    if(!check()){
        rebuild();return ;
    }
    ans=min(ans,calc());
    rebuild();
}

void dfs(int step){
    if(step==n+1){
        dp();return;
    }
    if(a[1][step]){
        dfs(step+1);return;
    }
    dfs(step+1);
    a[1][step]=1;
    dfs(step+1);
    a[1][step]=0;
}

void Init(){
    read(n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            read(a[i][j]);
            b[i][j]=a[i][j];
        }
    }
}

void solve(){
    dfs(1);
    if(ans==INF) ans=-1;
    printf("Case %d: %d\n",cas,ans);
}

void reset(){
    ans=INF;
    memset(a,0,sizeof(a));//错误笔记:多测不清空,*****
    memset(b,0,sizeof(b));
}

int main(){
//  freopen("UVA11464.in","r",stdin);freopen("UVA11464.out","w",stdout);
    read(T);
    while(T--){
        ++cas;
        reset();
        Init();solve(); 
    }
    return 0;
}