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


    题目链接:http://codeforces.com/contest/812/problem/B

    题意 : 给出一个 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
    ", ans);
        return 0;
    }
    View Code

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

    #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
    ", ans+F-1);//每一层消耗的体力还要加上上楼梯花费的体力
        return 0;
    }
    View Code
  • 相关阅读:
    [Python] Read and Parse Files in Python
    [React] Write Compound Components
    [Python] Reuse Code in Multiple Projects with Python Modules
    [Parcel] Bundle a React App with Parcel
    [Javascript] Specify this using .call() or .apply()
    [Javascript] this in Function Calls
    [Python] Create a Log for your Python application
    [Python] Create Unique Unordered Collections in Python with Set
    [Python] Manipulate Data with Dictionaries in Python
    SVN:常用命令
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/6940112.html
Copyright © 2020-2023  润新知