#417 Div2 Problem B Sagheer, the Hausmeister (DFS && 枚举)

题意 : 给出一个 n (1?≤?n?≤?15)层的教学楼, 每一层楼包含 m (1?≤?m?≤?100)个房间, 另外每一层的两边还有楼梯口, 接下来有n 行每行有 m+2(包含楼梯口) 用0和1来表示这栋楼的信息, 0代表这个房间的灯没亮, 1代表亮, 现在保安在整栋楼的左下角的楼梯口, 他的目的是关掉这栋楼所有的灯, 而且保安在上楼时他所在的当前楼层灯需全灭才能继续上楼, 而且每经过一个房间和上下楼梯都需要消耗1分钟, 问你最后最少需要多少分钟才能将整栋楼的灯关掉(注意灯全灭的楼层可以不必理会)!还有保安在关掉所有灯后就不会进行任何移动操作了!

分析 : 这题的关键是保安上楼时的决策, 即若保安现在左楼梯, 那他到底是关灯后下一层通过右楼梯走上上一层(这时耗时就是m+1), 还是先去关掉这一层所有的灯再走回左边楼梯上楼。由于这题楼层最多只有15层, 如果枚举每一层保安所有可能的走法那也就是2^15次方的复炸度, 可以接受, 所以可以采用DFS来枚举所有保安走法即可, 但是这里需要注意楼顶的层数并不一定是n, 因为可能在某一层例如第k层以后, 上面的灯就全都是灭的, 那保安就没必要继续上楼了, 枚举到第k层即可!

瞎想 : 可否贪心模拟?我一开始是考虑对于每一层保安所在的楼梯口进行贪心策略, 看通过哪一个楼梯口上楼消耗的时间更短, 但是挂在了第九个用例, 因为只考虑了当前楼层, 而没有结合以后楼层的情况进行考虑, 所以并不是最优, 说到这里, 这就有点DP的味道了!的确, 看了大佬们的代码, 看到了很多用DP解决。

瞎搞 : 其实贪心是可以很快写出来的, 又是没有使用模块化思想, 代码又长又臭, Debug了挺久。还有就是又没有考虑清楚当前的贪心策略会不会有BUG和没有考虑清楚顶楼情况, 导致代码写出来比赛已经OVER了 /(ㄒoㄒ)/~~, 最后还错了!!!

贪心错误做法:

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define lowbit(i) (i&(-i))
using namespace std;
const int INF = 0x3f3f3f3f;
int main(void)
{
    int G[20][1000];
    int n, m;
    bool flag;
    int cnt = 0;
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++){
        flag = false;
        for(int j=1; j<=m+2; j++){
            char ch;
            scanf("%c", &ch);
            if(isdigit(ch)) G[i][j] = ch-‘0‘;
            else j--;
            if(G[i][j]==1) flag = true;
        }
        if(flag && !cnt) cnt = i;
    }
    bool L = true;
    bool even;
    if((m+2)%2==0) even = true;
    else even = false;
    int ans;
    if(cnt==0) {puts("0");return 0;}
    else ans = n-cnt;
    //printf("%d  %d", cnt, ans);puts("");
    for(int i=n; i>=1; i--){
        if(i==cnt){
            if(L){
                int temp = -1;
                for(int j=m+2; j>=1; j--){
                    if(G[i][j]==1){
                        temp = j;
                        break;
                    }
                }
                if(temp==-1);
                else{
                    ans+=temp-1;
                }
            }else{
                int temp = -1;
                for(int j=1; j<=m+2; j++){
                    if(G[i][j]==1){
                        temp = j;
                        break;
                    }
                }
                if(temp==-1);
                else{
                    ans+=(m+2)-temp;
                }
            }
            break;
        }
        if(L){
            int temp = -1;
            for(int j=m+2; j>=1; j--){
                if(G[i][j]==1){
                    temp = j;
                    break;
                }
            }
            if(temp==-1);
            else{
                if(even){
                    if(temp>(m+2)/2){
                        ans+=m+1;
                        L = false;
                    }else{
                        ans+=temp-1;
                        ans+=temp-1;
                    }
                }else{
                    if(temp>((m+2)/2) + 1){
                        ans+=m+1;
                        L = false;
                    }else{
                        ans+=temp-1;
                        ans+=temp-1;
                    }
                }
            }
        }else{
            int temp = -1;
            for(int j=1; j<=m+2; j++){
                if(G[i][j]==1){
                    temp = j;
                    break;
                }
            }
            if(temp==-1);
            else{
                if(even){
                    if(temp<=(m+2)/2){
                        ans+=m+1;
                        L = true;
                    }else{
                        ans+=(m+2)-temp;
                        ans+=(m+2)-temp;
                    }
                }else{
                    if(temp<=((m+2)/2) + 1){
                        ans+=m+1;
                        L = true;
                    }else{
                        ans+=(m+2)-temp;
                        ans+=(m+2)-temp;
                    }
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

以下代码枚举做法, 由于有黏贴贪心时所写的代码, 所以又长又臭, 凑合着看吧

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define lowbit(i) (i&(-i))
using namespace std;
const int INF = 0x3f3f3f3f;
LL ans = INF;
int F;
int G[20][1000];
int n, m;
bool flag;
int cnt = 0;
void dfs(bool pre, bool now, int x, LL sum)//参数分别代表上一层所在的楼梯口位置, 和当前将要去往的楼梯口位置, 当前楼层数, 以及耗费了多少时间
{
    if(pre){//如果上一层是在左楼梯
        if(x==F){//如果在顶楼, 需要特殊处理
            int tmp = -1;
            for(int j=m+2; j>=1; j--){
                if(G[x][j]==1){
                    tmp = j;
                    break;
                }
            }
            if(tmp!=-1)sum+=tmp-1;
        }else{
            if(now){
                int tmp = -1;
                for(int j=m+2; j>=1; j--){
                    if(G[x][j]==1){
                        tmp = j;
                        break;
                    }
                }
                if(tmp!=-1){
                    sum += 2*(tmp-1);
                }
            }else{
                sum += m+1;
            }
        }
    }else{
        if(x==F){
            int tmp = -1;
            for(int j=1; j<=m+2; j++){
                if(G[x][j]==1){
                    tmp = j;
                    break;
                }
            }
            if(tmp!=-1) sum+=(m+2)-tmp;
        }else{
            if(now){
                sum += m+1;
            }else{
                int tmp = -1;
                for(int j=1; j<=m+2; j++){
                    if(G[x][j]==1){
                        tmp = j;
                        break;
                    }
                }
                if(tmp!=-1){
                    sum += 2*(m+2 - tmp);
                }
            }
        }
    }
    if(x!=F){
        dfs(now, true, x+1, sum);
        dfs(now, false, x+1, sum);
    }else{
        if(sum<ans) ans = sum;
        return;
    }
}
int main(void)
{
    scanf("%d%d", &n, &m);
    for(int i=n; i>=1; i--){
        flag = false;
        for(int j=1; j<=m+2; j++){
            char ch;
            scanf("%c", &ch);
            if(isdigit(ch)) G[i][j] = ch-‘0‘;
            else j--;
            if(G[i][j]==1) flag = true;
        }
        if(flag && !cnt) cnt = i;
    }
    bool L = true;
    if(cnt==0) {puts("0");return 0;}//所有楼层都是灯灭的
    else F = cnt;//记录有效顶楼
    dfs(true, true, 1, 0);//从第一层去往左楼梯上楼
    dfs(true, false, 1, 0);//从第一层去往右楼梯上楼
    printf("%lld\n", ans+F-1);//每一层消耗的体力还要加上上楼梯花费的体力
    return 0;
}

时间: 2024-11-08 23:01:49

#417 Div2 Problem B Sagheer, the Hausmeister (DFS && 枚举)的相关文章

#417 Div2 Problem C Sagheer and Nubian Market (二分 &amp;&amp; std::accumulate)

题意 : 给你 n 件物品和你拥有的钱 S, 接下来给出这 n 件物品的价格, 这些物品的价值不是固定不变的, 价格的变化公式是 a[i]+k*i (i代表第 i 件物品, k 代表你选择买的物品数量, a[i]为物品的底价), 现问你最多能够买多少件物品和所买物品总和, 输出时应该使得所买物品总和尽量小 分析 : 如果我当前能买 k 件物品, 那我肯定能买数量小于 k 的物品, 如果我当前买不起 k 件物品, 那我肯定也不能买比 k 件要多的物品.所以可以考虑二分解法, 在1~n之间二分查找

Codeforces Round #417 (Div. 2) B. Sagheer, the Hausmeister(DP)

题目链接:Codeforces Round #417 (Div. 2) B. Sagheer, the Hausmeister 题意: 有n层楼,每层有m个房间,每层的两边是楼梯. 现在有一个人站在左下角,这个人必须将这一层的灯关闭后才能去另外一层. 每移动一次需要1分钟,问关闭所有灯需要多少时间. 题解: 考虑DP[i][j]表示当前已经关闭了第i层全部的灯,j=0时表示在这一层的最左边,j=1时表示在这一层的最右边. 然后推上去就行了.最后讨论一下特殊情况. 1 #include<bits/

Codeforces Round #417 (Div. 2) A. Sagheer and Crossroads 模拟 枚举

Codeforces Round #417 (Div. 2) A. Sagheer and Crossroads 模拟  枚举 题意 一个红绿灯 按逆时针方向一次给出各个路口的左转,直行,右转,以及行人车道让你判断,汽车是否有可能撞到行人 注意 当前车道的左转有可能撞到别的车道的行人的 题解 一大堆特判 1 #include <cstdio> 2 #include <cmath> 3 #include <cstdlib> 4 #include <cstring&g

CodeForce-812B Sagheer, the Hausmeister(DFS)

Sagheer, the Hausmeister CodeForces - 812B 题意:有一栋楼房,里面有很多盏灯没关,为了节约用电小L决定把这些灯都关了. 这楼有 n 层,最左边和最右边有楼梯.每一层有 m 个房间排成一排.这栋楼可以被表示成一个 n 行 m?+?2 列的矩阵,其中每行第一个和最后一个格点表示楼梯, 剩余 m 个格点表示房间. 现在小L在最底层的最左边楼梯,他想要关掉所有的灯.他每次可以走到相邻的房间,如果在楼梯口可以上下楼梯.他打算关掉所有开着的灯,在他没有将一层的所有灯

AC日记——Sagheer, the Hausmeister codeforces 812b

812B - Sagheer, the Hausmeister 思路: 搜索: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 20 #define maxm 105 #define INF 0x7fffffff int n,m,deep[maxn][2],num[maxn],

Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree(树上Nim)

题目链接:Codeforces Round #417 (Div. 2) E. Sagheer and Apple Tree 题意: 给你一棵树,每个节点有a[i]个苹果,有两个人要在这个树上玩游戏. 两个人轮流操作,谁不能操作谁就输了. 这个树有一个特性:叶子到根的距离的奇偶性相同. 每次操作可以选一个节点i,和一个数x,x小于当前节点i的苹果数. 对于节点i,如果是叶子节点,就将这x个苹果吃掉. 如果是非叶子节点,就将这x个苹果移向节点i的任意儿子节点. 现在第二个操作的人要交换两个节点的苹果

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序

Codeforces Round #417 (Div. 2) C. Sagheer and Nubian Market 二分答案 +排序 题意 有 a[ i ] 个数 要求选最多的数 使其和不超过 S ,且在此情况下,和最小选最多数情况下 和最小 且 每个数有加成 如果选了 k个数 那么加成后 就是 a[ i ] + k*i ; 题解 二分mid 表示选了个数 加成一下,将加成以后结果排序一下 , 若前 mid数 和大于 s 则此方案不可行 PS 要用 long long ..... 还有 co

HDU 4068 dfs枚举

SanguoSHA Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 944    Accepted Submission(s): 520 Problem Description Sanguosha has a singled version. Two players each select N heroes and start fight

POJ 1753 Flip Game (DFS + 枚举)

题目:http://poj.org/problem?id=1753 这个题在开始接触的训练计划的时候做过,当时用的是DFS遍历,其机制就是把每个棋子翻一遍,然后顺利的过了,所以也就没有深究. 省赛前一次做PC2遇到了几乎一模一样的题,只不过是把棋盘的界限由4X4改为了5X5,然后一直跑不出结果来,但是当时崔老湿那个队过了,在最后总结的时候,崔老湿就说和这个题一样,不过要枚举第一行进行优化. 我以为就是恢复第一行然后第二行以此类推,不过手推一下结果是6不是4,就知道这个有问题. 问了崔老湿,问了+