UVa 1603 破坏正方形 (Square Destroyer)

题目:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxs = 60;  // 25 + 16 + 9 + 4 + 1 = 55;
const int maxm = 60;  // 2 * 5 * (5 + 1) = 60;
int n, m;
int best;
int exist[maxm];
int size[maxs];
int fullSize[maxs];
int contain[maxs][maxm];

inline int matchCount() {
    return 2 * n * (n + 1);
}

inline int SquareCount() {
    int ret = 1;
    for(int i = 2; i <= n; i++) {
        ret += i * i;
    }
    return ret;
}

inline int rowMatch(int x, int y) {
    return (2 * n + 1) * x + y;
}

inline int colMatch(int x, int y) {
    return (2 * n + 1) * x + y + n;
}

void init() {
    cin >> n >> m;
    for(int i = 0; i < matchCount(); i++) exist[i] = 1;
    while(m--) {
        int a;
        cin >> a;
        exist[a - 1] = 0;
    }    
    //长度为1开始
    int cnt = 0;
    memset(contain, 0, sizeof(contain));
    for(int i = 1; i <= n; i++) {
        for(int x = 0; x <= n - i; x++) {
            for(int y = 0; y <= n - i; y++) {
                //大小
                size[cnt] = 0;
                fullSize[cnt] = 4 * i;
                for(int p = 0; p < i; p++) {
                    int _top = rowMatch(x    , y + p);
                    int _bot = rowMatch(x + i, y + p);
                    int _lef = colMatch(x + p, y    );
                    int _rig = colMatch(x + p, y + i);
                    contain[cnt][_top] = 1;
                    contain[cnt][_bot] = 1;
                    contain[cnt][_lef] = 1;
                    contain[cnt][_rig] = 1;
                    size[cnt] += exist[_top] + exist[_bot] + exist[_lef] + exist[_rig];
                }
                ++cnt;
            }
        }
    }
}

int findSquare() {
    for(int i = 0; i < SquareCount(); i++) {
        if(fullSize[i] == size[i]) return i;
    }
    return -1;
}

void dfs(int d) {
    if(d >= best) return;
    int s = findSquare();
    if(s == -1) {
        best = d;
        return;
    }
    for(int i = 0; i < matchCount(); i++) {
        if(contain[s][i]) {
            for(int j = 0; j < SquareCount(); j++) {
                if(contain[j][i]) size[j]--;
            }
            dfs(d + 1);
            for(int j = 0; j < SquareCount(); j++) {
                if(contain[j][i]) size[j]++;
            }
        }
    }
}

int solve() {
    init();
    best = n * n;
    dfs(0);
    return best;
}


int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin >> T;
    while(T--) {
        cout << solve() << endl;
    }
    return 0;
}

总结
这道题和前面做的UVa 1343一样,都是给一个类似于二位数组的一个格式,如果直接利用二维数组存,处理起来都不方便,
根据刘汝佳的思路,以后遇到类似的题,可以转化为一维数组,本题的思路也非常巧妙

先当所有火柴都存在,然后输入的火柴不存在。
然后再一一列举所有的正方形,根据正方形左上角的坐标算出占据的火柴数,给出其最大大小和现大小
之后利用dfs搜索再回溯遍历所有情况找到需要的最小破坏火柴数

搜索与回溯的框架不难。
本题主要是连接火柴和正方形之间的关系,网上其他代码大多数均很复杂。
刘汝佳的做法如上,自己也实现了一遍,由于分类专栏的原因,虽不是自己的代码还是贴出来了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值