【UVA】10318-Security Panel(DFS 回溯)

比较纠结的一道题,改了好几次才对。

首先需要知道的就是每个点如果重复点2次是没有任何意义的,所以一个点只有选或者不选,那么时间复杂度最大为2^25

毫无疑问超过了允许的范围,那么考虑减枝。

由于是3 X 3 的改变范围,所以如果 当前走到了第三行,那么就没办法更改第一行的状态,如果走到了第四行就无法更改第一 二行的状态,所以如果这个时候第一 二行

还没改成亮的它永远也不可能亮了。

最后一个就是需要输出按开关的次数最小的方案,一开始没看见,WA了好几次。。

14171735 10318 Security Panel Accepted C++ 0.076 2014-09-09 11:49:25

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,OK;
int mat[15];
const int dir[11][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,0},{0,1},{1,-1},{1,0},{1,1}};
int Map[30];
int rote[30],_rote[30];
bool Input(){
    scanf("%d%d",&n,&m);
    if(!n && !m) return false;
    for(int i = 0 ,k = 0; i < 3 ; i++){
        char str[10];
        scanf("%s",str);
        for(int j = 0 ; j < 3 ; j ++){
            if(str[j] == '.')
                mat[k++] = 0;
            else if(str[j] == '*')
                mat[k++] = 1;
        }
    }
    return true;
}
void DFS(int pos,int cur){/*位置,n行,m列,当前按了几个按钮*/
    int x = pos / m;
    int y = pos % m;
    if(pos == 3 * m){
        for(int i = 0 ; i < m ;i ++)
            if(Map[i] != 1)
                return ;
    }
    if(pos == 4 * m){  /*在第四行,前面2行的情况就固定了*/
        for(int i = 0 ; i < 2 * m; i++)
            if(Map[i] != 1)
                return ;
    }
    if(pos == m * n){
        for(int i = 0 ; i < pos ; i++)
            if(Map[i] != 1) return ;
        if(cur < OK){
            OK = cur;
            memcpy(_rote,rote,sizeof(rote));
        }
        return ;
    }
    /*是否对这个点进行更改,或者不更改*/
    rote[pos] = 0;
    DFS(pos + 1,cur);  /*不更改直接走下一个点*/
    /*对这个点进行更改*/
    for(int i = 0 ; i < 9 ; i++){
        int _x = x + dir[i][0];
        int _y = y + dir[i][1];
        if(_x >= 0 && _x < n && _y >= 0 && _y < m && mat[i]){
             int _pos = _x * m + _y;
             Map[_pos] = - Map[_pos];
        }
    }
    rote[pos] = 1;
    DFS(pos + 1,cur + 1);
    /*记得把状态改回去*/
    for(int i = 0 ; i < 9 ; i++){
        int _x = x + dir[i][0];
        int _y = y + dir[i][1];
        if(_x >= 0 && _x < n && _y >= 0 && _y < m && mat[i]){
             int _pos = _x * m + _y;
             Map[_pos] = - Map[_pos];
        }
    }
    return ;
}
int main(){
    int Case = 1;
    while(Input()){
        memset(Map,-1,sizeof(Map));
        memset(rote,0,sizeof(rote));
        OK = 100;
        DFS(0,0);
        printf("Case #%d\n",Case++);
        if(OK < 100){
            int k = 0;
            for(int i = 0 ; i < n * m ; i++){
                if(_rote[i]){
                    if(k) printf(" ");
                        printf("%d",i + 1);
                    k++;
                }
            }
            printf("\n");
        }
        else
            printf("Impossible.\n");
    }
    return 0;
}
时间: 2024-10-13 00:53:10

【UVA】10318-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

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

uva 11218 KTV(DFS+回溯)

uva 11218 KTV One song is extremely popular recently, so you and your friends decided to sing it in KTV. The song has 3 characters, so exactly 3 people should sing together each time (yes, there are 3 microphones in the room). There are exactly 9 peo

UVa 129 Krypton Factor (DFS &amp;&amp; 回溯)

题意 : 如果一个字符串包含两个相邻的重复子串,则称它是"容易的串",其他串称为"困难的 串".例如,BB.ABCDACABCAB.ABCDABCD都是容易的串,而D.DC.ABDAB. CBABCBA都是困难的串.程序从输入中读取多行数据,每行包括两个整数n和L(即按此顺序给出),其中n > 0,L的范围是1 ≤ L ≤ 26.根据这些输入,程序要按照字母表升序打印出第n个"hard"字串(由字母表中的前L个字母构成),并在接下来的一行打

uva10318 Security Panel (dfs+剪枝)

题意: 有一个r*c的矩阵上选择一些格子进行"点亮"操作,使得最终所有格子都是"亮"的状态.初始时矩阵上面的所有格子是暗的,从左上到右下,编号从1开始. 现在我们给出一个3*3的矩阵,作为按钮规则: 例如: **. .*. *.. 也就是你按任意按钮,都把这个按钮当作是这个3*3矩阵的中心,按照这个规则,也就是按一个按钮,则这个按钮周围的 * 的位置,按照该规则,状态发生改变(如果它已经没有上一行了则忽略) 给出r,c代表几行几列 然后给出一个固定的3*3的矩阵,表

UVA 23 Out of 5(DFS+回溯)

Problem I 23 Out of 5 Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB Your task is to write a program that can decide whether you can find an arithmetic expression consisting of five given numbers (1<=i<=5) tha

UVA How Big Is It? (DFS+回溯)

 How Big Is It?  Ian's going to California, and he has to pack his things, including his collection of circles. Given a set of circles, your program must find the smallest rectangular box in which they fit. All circles must touch the bottom of the bo

poj1270Following Orders(拓扑排序+dfs回溯)

题目链接: 啊哈哈,点我点我 题意是: 第一列给出所有的字母数,第二列给出一些先后顺序.然后按字典序最小的方式输出所有的可能性... 思路: 总体来说是拓扑排序,但是又很多细节要考虑,首先要按字典序最小的方式输出,所以自然输入后要对这些字母进行排列,然后就是输入了,用scanf不能读空格,所以怎么建图呢??设置一个变量判断读入的先后顺序,那么建图完毕后,就拓扑排序了,那么多种方式自然就是dfs回溯了..那么这个问题就得到了解决.. 题目: Following Orders Time Limit:

CodeForces 550B Preparing Olympiad(DFS回溯)

[题目链接]:click here~~ [题目大意] 一组题目的数目(n<=15),每个题目有相应的难度,问你选择一定的题目(大于r个且小于l个)且选择后的题目里最小难度与最大难度差不小于x,求选择方案数. [解题思路]: DFS+回溯. 先发一发比较拙的代码: #include <bits/stdc++.h> using namespace std; const int N=1e5+10; int num[N],mum[N]; int n,m,q,t,l,r; int top,ans,