2022年信奥赛C++提高组csp-s初赛真题及答案解析(完善程序第2题)

2022年信奥赛C++提高组csp-s初赛真题及答案解析(完善程序第2题)

第2题

(容器分水) 有两个容器,容器 1 的容量为为 a 升,容器 2 的容量为 b 升;同时允许下列的三种操作,分别为:

  1. FILL(i):用水龙头将容器 i(i∈1,2)灌满水;
  2. DROP(i):将容器 i 的水倒进下水道;
  3. POUR(i,j):将容器 i 的水倒进容器 j(完成此操作后,要么容器 j 被灌满,要么容器 i 被清空)。

求只使用上述的两个容器和三种操作,获得恰好 c 升水的最少操作数和操作序列。上述 a、b、c 均为不超过 100 的正整数,且 c≤max{a,b}。

试补全程序。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
 
int f[N][N];
int ans;
int a, b, c;
int init;
 
int dfs(int x, int y) {
    if (f[x][y] != init)
        return f[x][y];
    if (x == c || y == c)
        return f[x][y] = 0;
    f[x][y] = init - 1;
    f[x][y] = min(f[x][y], dfs(a, y) + 1);
    f[x][y] = min(f[x][y], dfs(x, b) + 1);
    f[x][y] = min(f[x][y], dfs(0, y) + 1);
    f[x][y] = min(f[x][y], dfs(x, 0) + 1);
    int t = min(a - x, y);
    f[x][y] = min(f[x][y], ①);
    t = min(x, b - y);
    f[x][y] = min(f[x][y], ②);
    return f[x][y];
}
 
void go(int x, int y) {
    if (③)
        return;
    if (f[x][y] == dfs(a, y) + 1) {
        cout << "FILL(1)" << endl;
        go(a, y);
    } else if (f[x][y] == dfs(x, b) + 1) {
        cout << "FILL(2)" << endl;
        go(x, b);
    } else if (f[x][y] == dfs(0, y) + 1) {
        cout << "DROP(1)" << endl;
        go (0, y);
    } else if (f[x][y] == dfs(x, 0) + 1) {
        cout << "DROP(2)" << endl;
        go(x, 0);
    } else {
        int t = min(a - x, y);
        if(f[x][y] == ④) {
            cout << "POUR(2,1)" << endl;
            go(x + t, y - t);
        } else {
            t = min(x, b - y);
            if (f[x][y] == ⑤) {
                cout << "POUR(1,2)" << endl;
                go(x - t, y + t);
            } else
                assert(0);
        }
    }
}
 
int main() {
    cin >> a >> b >> c;
    ans = 1 << 30;
    memset(f, 127, sizeof f);
    init = **f;
    if ((ans = dfs (0, 0)) == init - 1)
        cout << "impossible";
    else {
        cout << ans << endl;
        go (0, 0);
    }
}
  1. ①处应填()

    A. dfs(x + t, y - t) + 1

    B. dfs(x + t, y - t) - 1

    C. dfs(x - t, y + t) + 1

    D. dfs(x - t, y + t) - 1

  2. ②处应填()

    A. dfs(x + t, y - t) + 1

    B. dfs(x + t, y - t) - 1

    C. dfs(x - t, y + t) + 1

    D. dfs(x - t, y + t) - 1

  3. ③处应填()

    A. x == c || y == c

    B. x == c && y == c

    C. x >= c || y >= c

    D. x >= c && y >= c

  4. ④处应填()

    A. dfs(x + t, y - t) + 1

    B. dfs(x + t, y - t) - 1

    C. dfs(x - t, y + t) + 1

    D. dfs(x - t, y + t) - 1

  5. ⑤处应填()

    A. dfs(x + t, y - t) + 1

    B. dfs(x + t, y - t) - 1

    C. dfs(x - t, y + t) + 1

    D. dfs(x - t, y + t) - 1

分析:

本题使用记忆化搜索(DFS)计算最少操作数,并通过递归输出操作序列。

  • 状态定义 :f[x][y] 表示两个容器当前水量分别为 x 和 y 时,达到任一容器水量为 c 的最少操作数。
  • DFS 过程 :对每种操作(FILL、DROP、POUR)进行状态转移,取最小值。
    • 对于 POUR(2,1),倒水量 t = min(a - x, y),转移到 (x+t, y-t),操作数加 1。
    • 对于 POUR(1,2),倒水量 t = min(x, b - y),转移到 (x-t, y+t),操作数加 1。
  • GO 过程 :根据 f[x][y] 的值逆向推导操作序列,直到达到目标状态(x==c || y==c)。
答案及题解:
  1. ①对应 POUR(2,1) 的状态转移,应为 dfs(x+t, y-t) + 1,选 A。
  2. ②对应 POUR(1,2) 的状态转移,应为 dfs(x-t, y+t) + 1,选 C。
  3. ③为递归终止条件,即任一容器水量为 c,选 A。
  4. ④判断是否为 POUR(2,1) 转移而来,应比较 f[x][y] == dfs(x+t, y-t) + 1,选 A。
  5. ⑤判断是否为 POUR(1,2) 转移而来,应比较 f[x][y] == dfs(x-t, y+t) + 1,选 C。

专栏推荐:信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新)
https://blog.csdn.net/weixin_66461496/category_13125089.html


各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

1、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html

2、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新)
https://blog.csdn.net/weixin_66461496/category_13125089.html

3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html

4、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
进化中的刀盾兽1 小时前
从零实现 C++ Json-Rpc(十):把消息交给真实连接——MuduoConnection 与 ConnectionFactory
c++·rpc
青瓦梦滋8 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
CodeYp201913 小时前
第15讲:二叉搜索树
开发语言·c++·二叉搜索树
pipixia2003314 小时前
C++继承面试四连问:内存叠加、私有继承、sizeof、权限重映射
c++·面试·嵌入式·继承·面向对象·对象模型
牵猫散步的鱼儿17 小时前
C++ 内存分区
c++
choumin17 小时前
C++ 标准容器为什么不能存引用
c++·容器·引用类型
谙弆悕博士17 小时前
用 C 写了个 Windows 聊天室,踩了几个多线程和控制台的坑
c语言·开发语言·c++·windows·网络编程·聊天室
stolentime18 小时前
CF2277E Tree Guessing题解
c++·算法·贪心算法·交互·ad-hoc
syagain_zsx19 小时前
ODB 与 MySQL:C++ 里的 ORM 实践(类即表、事务铁律与查询封装)
开发语言·数据库·c++·mysql·工具库·1024程序员节
小鱼仙官19 小时前
使用Qt封装C/C++ 动态库 用于第三方调用
c语言·c++·qt