uva10318 Security Panel (dfs+剪枝)

题意:

有一个r*c的矩阵上选择一些格子进行“点亮”操作,使得最终所有格子都是“亮”的状态。初始时矩阵上面的所有格子是暗的,从左上到右下,编号从1开始。

现在我们给出一个3*3的矩阵,作为按钮规则:

例如:

**.

.*.

*..

也就是你按任意按钮,都把这个按钮当作是这个3*3矩阵的中心,按照这个规则,也就是按一个按钮,则这个按钮周围的 * 的位置,按照该规则,状态发生改变(如果它已经没有上一行了则忽略)

给出r,c代表几行几列

然后给出一个固定的3*3的矩阵,表示按钮的规则

问最少按哪几个按钮,使得全部按钮都亮。

思路:

直接一行一行的深搜求解。每个按钮的状态只有两种点亮和不点亮。

但是最多有2^25种状态,还是非常庞大的。

所以需要有一个剪枝,就是你已经遍历到第x行,如果第x-2行还有没亮的按钮,则就直接退出,因为一个按钮最多影响到它上一行,上两行没亮的就永远不会亮了。

AC代码

#include <cstdio>
#include <cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int dx[] = {-1,-1,-1, 0, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1,-1, 0, 1,-1, 0, 1};
const int N = 5;
char str[N];
int pattern[3][3], grid[N][N];
int r, c, minv, ans[30], pressed[30];
int state[N][N];
bool check(int x) {
    if(x < 0) return true;
    for(int i = 0; i <= x; i++) {
        for(int j = 0; j < c; j++) {
            if(!state[i][j]) return false;
        }
    }
    return true;
}
void func(int x, int y) {
    int nx, ny;
    for(int i = 0; i < 9; i++) {
        if(pattern[1+dx[i]][1+dy[i]]) {
            nx = x+dx[i], ny = y+dy[i];
            if(nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
            state[nx][ny] = !state[nx][ny];
        }
    }
}
void dfs(int x, int y, int cur) {
    if(y == c) {
        if(x == r-1 && check(x)) {
            if(minv > cur) {
                minv = cur;
                memcpy(ans, pressed, sizeof(ans));
            }
        }else if(x < r-1 && check(x-2)) {
            dfs(x+1, 0, cur);
        }
        return ;
    }
    //select
    pressed[cur] = x*c + y + 1;
    func(x, y);
    dfs(x, y+1, cur+1);
    func(x, y);

    //unselect
    dfs(x, y+1, cur);
}
int main() {
//    freopen("in.txt", "r", stdin);
    int cas = 1;
    while(scanf("%d%d", &r, &c) != EOF && (r || c)) {
        //init
        memset(state, 0, sizeof(state));

        for(int i = 0; i < 3; i++) {
            scanf("%s", &str);
            for(int j = 0; j < 3; j++) {
                pattern[i][j] = (str[j] == ‘*‘);
            }
        }
        minv = INF;
        dfs(0, 0, 0);

        printf("Case #%d\n", cas++);
        if(minv != INF) {
            printf("%d", ans[0]);
            for(int i = 1; i < minv; i++) {
                printf(" %d", ans[i]);
            }puts("");
        }else {
            printf("Impossible.\n");
        }
    }
    return 0;
}
时间: 2024-10-07 20:49:12

uva10318 Security Panel (dfs+剪枝)的相关文章

UVA 10318 - Security Panel dfs 剪枝

UVA 10318 - Security Panel dfs 剪枝 ACM 题目地址:UVA 10318 - Security Panel 题意: 这题跟点灯的题目很像,点灯游戏选择一盏灯时会让它以及四周的灯改变状态. 但是我们有特殊的开开关技巧,它给出了改变状态的位置,而不是四周都改变. 问你从全部关着变成全部开着的最小开关步骤. 分析: 很明显,在一个位置上点两次或更多次是没有必要的,所以一个位置只有选择与不选择,用dfs即可,但如果暴力所有可能,复杂度是2^25,会超时,所以要剪枝. 由于

UVA-10318 Security Panel (DFS+剪枝)

题目大意:求将一个r*c的按钮矩阵由全部为关变成全部为开的最少按扭次数,每按一次开关能作用到的范围不定. 题目分析:开关问题.打眼一看就是BFS+位压缩,但是写出来之后TLE.用DFS不断更新最优解.最坏有2^25种情况,加两个剪枝: 一.每一个开关最多只能影响三行,当第now_r-2行仍然有开关关着,则这种方案不可能使所有按钮全部打开,剪掉(并且是主剪): 二.当当前总的按按钮次数大于已经达到的答案,则剪掉: 第二个剪枝效果不强,加不加都是26ms过,但不加第一个剪枝一定TLE. 这道题用BF

UVa 10318 Security Panel

题意:给你一个3*3的翻转模版,深色部分表示翻转,浅色部分不变.然后你可以在r*c的矩形里依照模版进行翻转,要求所有点亮所有块.输出最小的步骤. 思路:有一点比较好想.每个块至多被翻转一次,翻两次的效果是一样的.这样可以搜索,大约2^25,会超时.考虑剪枝.对于每次翻转,只会影响与它临近的几个块,也就是说如果在该块的往上数第2行之前有没亮的块,那么无论之后怎么样,最后一定不会全亮,因为后面的块根本不会影响到前面这些. 这里可以用二进制表示状态.代码写的比较糟乱. #include<cstdio>

ZOJ 1008 Gnome Tetravex (DFS + 剪枝)

Gnome Tetravex 题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=8 题意:有N*N个方格,每个方格分为上下左右四个部分,每个部分填数字.现在要求重排方块,使得每两个有边相连的方块对应的数字相同. 思路:就是一个简单的搜索,我想了个剪枝,将上下左右四个方向上每个数字对应的是哪几个方块记录下来,但是这个剪枝并没有起很大的作用,还是T了.后来才发现,如果有很多个方块是相同的,会重复搜索,所以需要将相同的方块一起处

Cubes(DFS+剪枝)

题意:给一个数N,求N最少由多少个数的立方构成,并输出这些数. 做法:DFS + 剪枝,剪枝的边界很很很重要! 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> int cub[400]; int ans[300]; int tp[300]; int n; int sum = 0x3f3f3f3f; //个数 void dfs(int le

hdu 4109 dfs+剪枝优化

求最久时间即在无环有向图里求最远路径 dfs+剪枝优化 从0节点(自己增加的)出发,0到1~n个节点之间的距离为1,mt[i]表示从0点到第i个节点目前所得的最长路径 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const

POJ 1564 Sum It Up (DFS+剪枝)

 Sum It Up Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 5820   Accepted: 2970 Description Given a specified total t and a list of n integers, find all distinct sums using numbers from the list that add up to t. For example, if t = 4

EOJ1981 || POJ1011 经典dfs+剪枝+奇怪的数据

题目:EOJ1981 || POJ1011   经典dfs+剪枝+奇怪的数据 Description George took sticks of the same length and cut them randomly until all partsbecame at most 50 units long. Now he wants to return sticks to the originalstate, but he forgot how many sticks he had origi

HDOJ 5113 Black And White DFS+剪枝

DFS+剪枝... 在每次DFS前,当前棋盘的格子数量的一半小于一种颜色的数量时就剪掉 Black And White Time Limit: 2000/2000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others) Total Submission(s): 194    Accepted Submission(s): 50 Special Judge Problem Description In mathematics,