11年福州 G 迭代加深+强剪枝 HDU 4127

刚开始想了一种奇怪的方法去贪心,因为不是正确的就不贴了,然后T了……
题解写的是IDA*,其实是迭代加深和剪枝。
剪枝的地方有几处:
1.估价函数剪枝,还剩几种颜色估计几步
2.无效剪枝,如果当前这个颜色已经没有就不用走这一步了

整体的思路是这样的
把原图按照颜色做一个连通块,然后原图可以分为三个部分:和(1,1)连通的点、和(1,1)连通的点相邻的点、其他点
那么,每次只在这些和(1,1)连通点相邻的点上选取颜色,然后就是一个接近暴力的过程。
因为数组稍多,重复访问不可承受。所以采取每次枚举当前变换成的颜色,然后标记掉相邻的相同颜色的点。
每个点用它的连通块标号来判断是否已经访问过,避免访问整个8*8数组的情况。   

失分点:
1. 根据数据范围应该猜测为搜索,然而一开始思路就错了。
2. 剪枝没有充分,特别是无效剪枝一块,不加就T了
学习处:
1. 搜索剪枝的范围会很小,大概猜测10以内为1s,20以内为2-3s
2. 剪枝分为:最优性剪枝、无效剪枝、估价函数剪枝等

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MAXN = 8 + 1;
int g[MAXN][MAXN], n;
bool vis[MAXN][MAXN], use[MAXN * MAXN];
int bccno[MAXN][MAXN], bcccnt, col[MAXN * MAXN];
int ans;
int dx[] = {-1, 0, 1, 0};
int dy[] = {0, -1, 0, 1};
bool validPos(int x, int y){if(x >= 0 && x < n && y >= 0 && y < n) return true; else return false;}
int predit()
{
    bool tcol[6];
    for(int i = 0 ; i < 6 ; i++) tcol[i] = false;
    int res = 0;
    for(int i = 1 ; i <= bcccnt ; i++) if(tcol[col[i]] == false && use[i] == false) tcol[col[i]] = true, res++;
    return res;
}
int getcnt(int c)
{
    int res = 0;
    for(int i = 0 ; i < n ; i++) {
        for(int j = 0 ; j < n ; j++) {
            if(g[i][j] == c && use[bccno[i][j]] == false) {
                int ok = 0;
                for(int k = 0 ; k < 4 ; k++) {
                    int tx = i + dx[k], ty = j + dy[k];
                    if(use[bccno[tx][ty]]) {
                        ok = 1;
                        break;
                    }
                }
                if(ok) res++;
            }
        }
    }
    return res;
}
bool dfs(int dep)
{
    int pre = predit();
//    printf("ans = %d, dep = %d, pre = %d\n", ans, dep, pre);
    if(dep == ans) {
        if(pre == 0) return true;
        else return false;
    }
    else if(dep + pre > ans) return false;
//        printf("dep = %d, use = ");
//        for(int i = 1 ; i <= bcccnt ; i++) printf("%d ", use[i]);
//        puts("");
    bool tuse[MAXN * MAXN];
    memcpy(tuse, use, sizeof use);
    for(int c = 0 ; c < 6 ; c++) {
        if(getcnt(c) == 0) continue;
        for(int i = 0 ; i < n ; i++) {
            for(int j = 0 ; j < n ; j++) {
                if(use[bccno[i][j]] == 0 && col[bccno[i][j]] == c) {
                    int ok = 0;
                    for(int k = 0 ; k < 4 ; k++) {
                        int tx = i + dx[k];
                        int ty = j + dy[k];
                        if(use[bccno[tx][ty]] == true) {
                            ok = 1;
                            break;
                        }
                    }
                    use[bccno[i][j]] = ok;
                }
            }
        }
      //  system("pause");
        if(dfs(dep + 1)) return true;
        memcpy(use, tuse, sizeof tuse);
    }

    return false;
}
void dfsbcc(int x, int y, int mark)
{
    for(int i = 0 ; i < 4 ; i++) {
        int tx = x + dx[i];
        int ty = y + dy[i];
        if(validPos(tx, ty) && g[x][y] == g[tx][ty] && bccno[tx][ty] == 0) {
            bccno[tx][ty] = mark;
            dfsbcc(tx, ty, mark);
        }
    }
}
int main()
{
    while(scanf("%d", &n) != EOF && n) {
        for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) scanf("%d", &g[i][j]);
        ans = 1;
        for(int i = 0 ; i < n ; i++) for(int j = 0 ; j < n ; j++) vis[i][j] = bccno[i][j] = 0;
        bcccnt = 0;
        for(int i = 0 ; i < n ; i++) {
            for(int j = 0 ; j < n ; j++) {
                if(bccno[i][j] == 0) {
                    bccno[i][j] = ++bcccnt;
                    dfsbcc(i, j, bcccnt);
                    col[bcccnt] = g[i][j];
                }
            }
        }
        for(int i = 1 ; i <= bcccnt ; i++) use[i] = false;
        use[1] = true;
        ans = 0;
        while(dfs(0) == false) ans++;
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值