1 条题解

  • 0

    题意分析

    一个约瑟夫环问题,对于输入的字符串,从开始依次进行报数,当报到N=1999N=1999时,删除对应的字符,字符串可以看作是首尾相连的环,直到剩余最后一个字符。如果剩余字符为?'?',则输出结果:YesYes;如果剩余字符为' '(空格),则输出结果:NoNo;否则输出结果:No commentsNo\ comments

    解题思路

    1. 问题本质:这是一个基于约瑟夫环问题的变种,需要按照固定规则(N=1999N=1999)循环删除字符,直到剩余最后一个字符。

    2. 关键特性

      • 环形处理:当到达字符串末尾时需回到开头继续
      • 动态变化:每次删除后字符串长度改变,影响后续计算
      • 结果判定:最后剩余字符决定输出(?'?'""" "或其他)
    3. 方法选择

      • 直接模拟法最适合本题数据规模(N30000N\leq30000
      • 数学解法虽高效但实现复杂,对本题收益不大

    实现步骤

    1. 输入处理

      • 读取所有输入文本,合并为连续字符序列
      • 去除换行符等非内容字符
    2. 模拟删除过程

      • 初始化当前位置为起始点
      • 循环执行直到剩余11个字符:
        a. 计算要删除的位置:(当前位置+1998) % 当前长度(当前位置 + 1998)\ \%\ 当前长度
        b. 删除该位置字符
        c. 更新当前位置为删除位置(考虑后续元素前移)
    3. 结果判定

      • 检查最后剩余字符:
        • ?'?'"Yes""Yes"
        • 空格 → "No""No"
        • 其他 → "No comments""No\ comments"
    4. 输出处理

      • 根据判定结果输出对应字符串

    代码实现

    
    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <climits>
    using namespace std;
    
    const int MAX_M = 100;
    const int MAX_N = 500;
    
    int main() {
        int M, N;
        scanf("%d %d", &M, &N);
        
        vector<vector<int> > fee(M + 1, vector<int>(N + 2, INT_MAX));
        vector<vector<int> > dp(M + 1, vector<int>(N + 2, INT_MAX));
        vector<vector<int> > prev(M + 1, vector<int>(N + 2, 0));
        
        // 读取每层每个房间的费用
        for (int i = 1; i <= M; ++i) {
            for (int j = 1; j <= N; ++j) {
                scanf("%d", &fee[i][j]);
            }
        }
        
        // 初始化第一层的DP值
        for (int j = 1; j <= N; ++j) {
            dp[1][j] = fee[1][j];
        }
        
        // 动态规划计算每一层的最小费用
        for (int i = 2; i <= M; ++i) {
            for (int j = 1; j <= N; ++j) {
                // 检查下方房间
                if (dp[i-1][j] != INT_MAX && dp[i-1][j] + fee[i][j] < dp[i][j]) {
                    dp[i][j] = dp[i-1][j] + fee[i][j];
                    prev[i][j] = j;
                }
                
                // 检查左邻房间
                if (j > 1 && dp[i][j-1] != INT_MAX && dp[i][j-1] + fee[i][j] < dp[i][j]) {
                    dp[i][j] = dp[i][j-1] + fee[i][j];
                    prev[i][j] = j-1;
                }
                
                // 检查右邻房间
                if (j < N && dp[i][j+1] != INT_MAX && dp[i][j+1] + fee[i][j] < dp[i][j]) {
                    dp[i][j] = dp[i][j+1] + fee[i][j];
                    prev[i][j] = j+1;
                }
            }
        }
        
        // 找到第M层的最小费用和对应的房间
        int min_cost = INT_MAX;
        int last_room = 0;
        for (int j = 1; j <= N; ++j) {
            if (dp[M][j] < min_cost) {
                min_cost = dp[M][j];
                last_room = j;
            }
        }
        
        // 回溯路径
        vector<int> path;
        int current_room = last_room;
        for (int i = M; i >= 1; --i) {
            path.push_back(current_room);
            current_room = prev[i][current_room];
        }
        
        // 输出路径(倒序)
        for (int i = path.size() - 1; i >= 0; --i) {
            printf("%d\n", path[i]);
        }
        
        return 0;
    }    
    
    • 1

    信息

    ID
    1360
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者