【枚举暴力】【UVA11464】 Even Parity

传送门

Description

  给你一个0/1矩阵,可以将矩阵中的0变成1,问最少经过多少此操作使得矩阵任意一元素四周的元素和为偶数。

Input

 第一行是一个整数T代表数据组数,每组数据包含以下内容:

  • 第一行是一个整数n,代表矩阵的行列数
  • 接下来n行每行n个用空格隔开的整数,代表矩阵元素。

Output

 对于每组数据输出一行,格式为Case X: ans

Sample Input

3
3
0 0 0
0 0 0
0 0 0
3
0 0 0
1 0 0
0 0 0
3
1 1 1
1 1 1
0 0 0

Sample Output

Case 1: 0
Case 2: 3
Case 3: -1

Hint

1≤n≤15,数据不超过30组。

Solution

考虑爆搜,显然超时。

考虑如果我们知道了前i行的信息,为了保证第i行是合法的,那么第i+1行放什么元素就被唯一确定了。

换句话说,只要确定了第一行的元素,通过数学归纳法易证,整个矩阵都被唯一确定了。

考虑第一行,只有2n种可能,由于n≤15,完全可以进行枚举。后面依据前面的元素进行判断,复杂度为O(n2),合并复杂度上届为O(2nn2),已经可以通过本题。

通过一些简单的剪纸,程序可以跑的飞快,40ms在lg rk1。

Code

#include<cstdio>
#include<cstring>
#define rg register
#define ci const int

inline void qr(int &x) {
    char ch=getchar(),lst=NULL;
    while(ch>‘9‘||ch<‘0‘) lst=ch,ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if (lst==‘-‘) x=-x;
}

char buf[20];
inline void write(int x,const char aft,const bool pt) {
    if(x<0) {putchar(‘-‘);x=-x;}
    int top=0;
    do {
        buf[++top]=x%10+‘0‘;
        x/=10;
    } while(x);
    while(top) putchar(buf[top--]);
    if(pt) putchar(aft);
}

template <typename T>
inline T mmax(const T &a,const T &b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T &a,const T &b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T &a) {if(a<0) return -a;return a;}

template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;}

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

int t,n,cnt,ans;
int MU[maxn][maxn];
int pos[maxn][maxn];

void clear();
void dfs(ci,ci);
void check(ci);

int main() {
    qr(t);
    while(t--) {
        clear();qr(n);
        for(rg int i=1;i<=n;++i) for(int j=1;j<=n;++j) qr(MU[i][j]);
        dfs(1,0);
        if(ans==INF) ans=-1;
        printf("Case %d: %d\n",++cnt,ans);
    }
    return 0;
}

void clear() {
    memset(MU,0,sizeof MU);
    memset(pos,0,sizeof pos);
    n=0;ans=INF;
}

void dfs(ci k,ci x) {
    if(x>=ans) return;
    if(k>n) {check(x);return;}
    if(!MU[1][k]) {
        pos[1][k]=0;dfs(k+1,x);
        pos[1][k]=1;dfs(k+1,x+1);
    }
    else {
        pos[1][k]=1;dfs(k+1,x);
    }
}

void check(int x) {
    for(rg int i=2;i<=n;++i) {
        rg int di=i-1;rg int ddi=di-1;
        for(rg int j=1;j<=n;++j) {
            if((pos[di][j-1]+pos[di][j+1]+pos[ddi][j])&1) pos[i][j]=1;else pos[i][j]=0;
            if(pos[i][j]!=MU[i][j]) {
                if(MU[i][j]) return;
                ++x;
                if(x>=ans) return;
            }
        }
    }
    for(rg int i=1;i<=n;++i) {
        if((pos[n][i-1]+pos[n][i+1]+pos[n-1][i])&1) return;
    }
    ans=x;
}

Summary

在答案依附于一个初始状态,且初始状态数可以枚举时,不妨考虑枚举初始状态,凭借此计算出终态。

这样做不仅应用于搜索题,事实上也应用于一部分DP中。

原文地址:https://www.cnblogs.com/yifusuyi/p/9425990.html

时间: 2024-10-31 04:23:12

【枚举暴力】【UVA11464】 Even Parity的相关文章

UVa11464 Even Parity (枚举子集)

链接:http://acm.hust.edu.cn/vjudge/problem/24665分析:枚举第0行的情况,接下来可以根据第0行计算出第1行,根据第1行计算出第2行...方法是当确定B[r][c]是0还是1时(前提要合法),根据B[r-1][c]的上,左,右3个元素之和来判断,如果出现将原来是1的变为0则不合法返回INF,最后统计下原来是0后来变为1的个数cnt,然后返回更新ans被改变元素的最小个数即可. 1 #include <cstdio> 2 #include <cstr

枚举 UVA 11464 Even Parity

题目传送门 1 /* 2 题意:求最少改变多少个0成1,使得每一个元素四周的和为偶数 3 枚举:枚举第一行的所有可能(1<<n),下一行完全能够由上一行递推出来,b数组保存该位置需要填什么 4 最后检查不同的数量,取最小值 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring> 9 using namespace std; 10 11 const int MAXN = 20;

uva 12325 枚举暴力 b

Some brave warriors come to a lost village. They are very lucky and find a lot of treasures and a big treasure chest, but with angry zombies. The warriors are so brave that they decide to defeat the zombies and then bring all the treasures back. A br

Uva11464 Even Parity

枚举每个格子的状态显然是不可能的. 思考发现,矩阵第一行的状态确定以后,下面的状态都可以递推出来. 于是状压枚举第一行的状态,递推全图的状态并判定是否可行. 1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<list> 8 usin

[AHOI2009][BZOJ1800] fly 飞行棋|枚举|暴力

1800: [Ahoi2009]fly 飞行棋 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1039  Solved: 864[Submit][Status][Discuss] Description 给出圆周上的若干个点,已知点与点之间的弧长,其值均为正整数,并依圆周顺序排列. 请找出这些点中有没有可以围成矩形的,并希望在最短时间内找出所有不重复矩形. Input 第一行为正整数N,表示点的个数,接下来N行分别为这N个点所分割的各个圆弧长度 O

5.20 考试 20 未完

水灾(sliker.cpp/c/pas) 1000MS  64MB 大雨应经下了几天雨,却还是没有停的样子.土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没. CCY所在的城市可以用一个N*M(N,M<=50)的地图表示,地图上有五种符号:". * X D S".其中"X"表示石头,水和人都不能从上面经过."."表示平原,CCY和洪水都可以经过."*"表示洪水开始地方(可能有多个地方开始

【BZOJ】【1050】【HAOI2006】旅行comf

枚举/暴力/Kruskal orz……我sb了……其实是sb题<_< 有一道题问的是最小极差生成树……(不记得是什么名字了,就是求最大边权与最小边权差最小的生成树)做法是枚举最小边,然后kruskal找最大边 这题同理,因为$m\leq 5000$,所以$m^2$的算法即可…… 1 /************************************************************** 2 Problem: 1050 3 User: Tunix 4 Language: C

概率论 --- Uva 11181 Probability|Given

Uva 11181 Probability|Given Problem's Link:   http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18546 Mean: n个人去逛超市,第i个人会购买东西的概率是Pi.出超市以后发现有r个人买了东西,问你每个人购买东西的实际概率是多少. analyse: 转换模型: 有n个员工,每个员工被选出来的概率是Pi.最后选出了r个,问你第i个员工在这r个中的概率是多少. 设: 事件A---

FZUOJ Problem 2178 礼物分配

Problem 2178 礼物分配 题目链接: Click Here~ Problem Description 在双胞胎兄弟Eric与R.W的生日会上,他们共收到了N个礼物,生日过后他们决定分配这N个礼物(numv+numw=N).对于每个礼物他们俩有着各自心中的价值vi和wi,他们要求各自分到的礼物数目|numv-numw|<=1,并且各自所衡量的礼物价值的差值|sumv-sumw|尽可能小,现在他们想知道最小的差值是多少.  Input 第一行为一个整数表示数据组数T. 接下来T组数组,每组