牛客题解 | water
1.牛客题解 | 5-血型遗传检测2.牛客题解 | 61-递归和动态规划-汉诺塔II3.牛客题解 | Anniversary4.牛客题解 | BST判定5.牛客题解 | CCNumber6.牛客题解 | CIDR去重7.牛客题解 | DNA序列8.牛客题解 | D塔29.牛客题解 | Fibonacci数列10.牛客题解 | K 的倍数11.牛客题解 | Kolakoski 序列12.牛客题解 | LRU Cache13.牛客题解 | LUCKY STRING14.牛客题解 | N-GCD15.牛客题解 | Numeric Keypad16.牛客题解 | Shopee的办公室(二)17.牛客题解 | Spring Outing18.牛客题解 | UTF-8 编码验证19.牛客题解 | Unix路径简化20.牛客题解 | bit count21.牛客题解 | bit位数22.牛客题解 | filename extension23.牛客题解 | geohash编码24.牛客题解 | ipv4地址白名单25.牛客题解 | ipv4地址白名单_126.牛客题解 | k倍多重正整数集合27.牛客题解 | n个数里出现次数大于等于n除以2的数28.牛客题解 | n个数里最小的k个
29.牛客题解 | water
30.牛客题解 | xor31.牛客题解 | ん...红茶?32.牛客题解 | 一封奇怪的信33.牛客题解 | 一组带数字编号的球,其中有两个编号只出现了一次,把它们找出来34.牛客题解 | 万万没想到之抓捕孔连顺35.牛客题解 | 万万没想到之聪明的编辑36.牛客题解 | 上台阶37.牛客题解 | 上高楼38.牛客题解 | 下厨房39.牛客题解 | 不想出差的HR40.牛客题解 | 不要二41.牛客题解 | 丢失的三个数42.牛客题解 | 两两配对差值最小43.牛客题解 | 两个子串44.牛客题解 | 两个整数二进制位不同个数45.牛客题解 | 两种排序方法46.牛客题解 | 中位数47.牛客题解 | 中缀表达式转后缀表达式48.牛客题解 | 丰收49.牛客题解 | 串的模式匹配50.牛客题解 | 之字形打印矩阵51.牛客题解 | 乔乔的包52.牛客题解 | 乘坐公交53.牛客题解 | 乘方取模54.牛客题解 | 买房55.牛客题解 | 买橘子56.牛客题解 | 买苹果57.牛客题解 | 买面包58.牛客题解 | 争吵59.牛客题解 | 二分图判定60.牛客题解 | 二分图判定_161.牛客题解 | 二分查找62.牛客题解 | 二叉搜索树判定63.牛客题解 | 二叉树的序列化64.牛客题解 | 二维数组打印65.牛客题解 | 二进制中有多少个166.牛客题解 | 交叉线67.牛客题解 | 交换查询68.牛客题解 | 交错01串69.牛客题解 | 交错序列70.牛客题解 | 代价71.牛客题解 | 任务调度72.牛客题解 | 优雅的点73.牛客题解 | 会话列表74.牛客题解 | 会话列表_175.牛客题解 | 伪正则表达式76.牛客题解 | 俄罗斯方块77.牛客题解 | 保卫方案78.牛客题解 | 保留最大的数79.牛客题解 | 信用卡推荐客户列表80.牛客题解 | 倒水81.牛客题解 | 倒着输出整数82.牛客题解 | 倒置字符串83.牛客题解 | 公交车84.牛客题解 | 公平划分85.牛客题解 | 公约数86.牛客题解 | 六一儿童节87.牛客题解 | 共享单车88.牛客题解 | 关灯游戏89.牛客题解 | 冒泡排序90.牛客题解 | 写一段程序判断IP字符串是否属于内网IP题目
解题思路
这是一道经典的倒水问题,需要通过BFS搜索来找到从初始状态到目标状态的最短路径。主要思路如下:
- 使用四维布尔数组 记录状态是否访问过
- 使用
tuple<int,int,int,int>
表示四个杯子的状态,简化状态传递 - 使用BFS搜索所有可能的状态转移,每次可以:
- 将任意杯子装满水
- 将任意杯子倒空
- 将一个杯子的水倒入另一个杯子
- 特殊情况处理:如果初始容量全为0且不等于目标状态,直接返回-1
代码
#include<bits/stdc++.h>
using namespace std;
bool mem[64][64][64][64] = {false};
bool equal(int s[4], int T[4]){
return (s[0]==T[0])&&(s[1]==T[1])&&(s[2]==T[2])&&(s[3]==T[3]);
}
int bfs(int S[4], int T[4]){
queue<tuple<int,int,int,int>> q;
auto x = make_tuple(0,0,0,0);
q.push(x);
mem[0][0][0][0] = true;
int step = 0, cap[4]={0};
while(!q.empty()){
int size = q.size();
while(size--){
tie(cap[0],cap[1],cap[2],cap[3]) = q.front(); q.pop();
if(equal(cap, T)){
return step;
}
for(int i=0; i<3; ++i){
switch(i){
case 0: // 将某个杯子倒满
for(int j=0, tmp=0; j<4; ++j){
tmp = cap[j];
cap[j] = S[j];
x = make_tuple(cap[0], cap[1], cap[2], cap[3]);
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]){
mem[cap[0]][cap[1]][cap[2]][cap[3]]=true;
q.push(x);
}
cap[j] = tmp;
}
break;
case 1: // 将某个杯子倒空
for(int j=0, tmp=0; j<4; ++j){
tmp = cap[j];
cap[j] = 0;
x = make_tuple(cap[0], cap[1], cap[2], cap[3]);
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]){
mem[cap[0]][cap[1]][cap[2]][cap[3]]=true;
q.push(x);
}
cap[j] = tmp;
}
break;
case 2: // 将杯子j倒向杯子z
for(int j=0; j<4; ++j){
int tmp1,tmp2,need;
for(int z=0; z<4; ++z){
if(j==z) continue;
tmp1=cap[j], tmp2=cap[z];
need = min(cap[j], S[z]-cap[z]);
cap[j] -= need;
cap[z] += need;
x = make_tuple(cap[0], cap[1], cap[2], cap[3]);
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]){
mem[cap[0]][cap[1]][cap[2]][cap[3]]=true;
q.push(x);
}
cap[j]=tmp1, cap[z]=tmp2;
}
}
}
}
}
++step;
}
return -1;
}
int main(){
int S[4]={0}, T[4]={0};
cin>> S[0] >> S[1] >> S[2] >> S[3];
cin>> T[0] >> T[1] >> T[2] >> T[3];
// 特殊情况处理
if(S[0]==0 && S[1]==0 && S[2]==0 && S[3]==0 && !equal(S,T)){
cout<< -1 << endl;
}else{
int ret = bfs(S, T);
cout<< ret << endl;
}
return 0;
}
import java.util.*;
public class Main {
static boolean[][][][] mem = new boolean[64][64][64][64];
static boolean equal(int[] s, int[] t) {
return s[0] == t[0] && s[1] == t[1] && s[2] == t[2] && s[3] == t[3];
}
static int bfs(int[] S, int[] T) {
Queue<int[]> q = new LinkedList<>();
q.offer(new int[]{0,0,0,0});
mem[0][0][0][0] = true;
int step = 0;
while(!q.isEmpty()) {
int size = q.size();
while(size-- > 0) {
int[] cap = q.poll();
if(equal(cap, T)) {
return step;
}
for(int i = 0; i < 3; i++) {
switch(i) {
case 0: // 将某个杯子倒满
for(int j = 0; j < 4; j++) {
int tmp = cap[j];
cap[j] = S[j];
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]) {
mem[cap[0]][cap[1]][cap[2]][cap[3]] = true;
q.offer(cap.clone());
}
cap[j] = tmp;
}
break;
case 1: // 将某个杯子倒空
for(int j = 0; j < 4; j++) {
int tmp = cap[j];
cap[j] = 0;
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]) {
mem[cap[0]][cap[1]][cap[2]][cap[3]] = true;
q.offer(cap.clone());
}
cap[j] = tmp;
}
break;
case 2: // 将杯子j倒向杯子z
for(int j = 0; j < 4; j++) {
for(int z = 0; z < 4; z++) {
if(j == z) continue;
int tmp1 = cap[j], tmp2 = cap[z];
int need = Math.min(cap[j], S[z]-cap[z]);
cap[j] -= need;
cap[z] += need;
if(!mem[cap[0]][cap[1]][cap[2]][cap[3]]) {
mem[cap[0]][cap[1]][cap[2]][cap[3]] = true;
q.offer(cap.clone());
}
cap[j] = tmp1;
cap[z] = tmp2;
}
}
}
}
}
step++;
}
return -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] S = new int[4];
int[] T = new int[4];
for(int i = 0; i < 4; i++) S[i] = sc.nextInt();
for(int i = 0; i < 4; i++) T[i] = sc.nextInt();
if(S[0] == 0 && S[1] == 0 && S[2] == 0 && S[3] == 0 && !equal(S,T)) {
System.out.println(-1);
} else {
System.out.println(bfs(S, T));
}
}
}
from collections import deque
def equal(s, t):
return s[0] == t[0] and s[1] == t[1] and s[2] == t[2] and s[3] == t[3]
def bfs(S, T):
mem = [[[[ False for _ in range(64)] for _ in range(64)] for _ in range(64)] for _ in range(64)]
q = deque([(0,0,0,0)])
mem[0][0][0][0] = True
step = 0
while q:
size = len(q)
for _ in range(size):
cap = list(q.popleft())
if equal(cap, T):
return step
for i in range(3):
if i == 0: # 将某个杯子倒满
for j in range(4):
tmp = cap[j]
cap[j] = S[j]
if not mem[cap[0]][cap[1]][cap[2]][cap[3]]:
mem[cap[0]][cap[1]][cap[2]][cap[3]] = True
q.append(tuple(cap))
cap[j] = tmp
elif i == 1: # 将某个杯子倒空
for j in range(4):
tmp = cap[j]
cap[j] = 0
if not mem[cap[0]][cap[1]][cap[2]][cap[3]]:
mem[cap[0]][cap[1]][cap[2]][cap[3]] = True
q.append(tuple(cap))
cap[j] = tmp
else: # 将杯子j倒向杯子z
for j in range(4):
for z in range(4):
if j == z:
continue
tmp1, tmp2 = cap[j], cap[z]
need = min(cap[j], S[z]-cap[z])
cap[j] -= need
cap[z] += need
if not mem[cap[0]][cap[1]][cap[2]][cap[3]]:
mem[cap[0]][cap[1]][cap[2]][cap[3]] = True
q.append(tuple(cap))
cap[j], cap[z] = tmp1, tmp2
step += 1
return -1
if __name__ == "__main__":
S = list(map(int, input().split()))
T = list(map(int, input().split()))
if S == [0,0,0,0] and not equal(S,T):
print(-1)
else:
print(bfs(S, T))
算法及复杂度分析
优化要点:
- 使用四维布尔数组替代哈希表,大幅提升访问效率
- 使用tuple简化状态表示和传递
- 使用switch-case结构清晰地划分三种操作
- 提前处理特殊情况(全0初始状态)
复杂度分析:
- 时间复杂度:,其中 是状态数(最大 ), 是状态转移数
- 空间复杂度:,使用固定大小的四维数组
合集:
牛客笔试大厂真题题解1
分类:
牛客笔试大厂真题题解1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)