分酒问题(DFS解法)
题目大概是这样:
已知有三个容量分别为3千克、5千克和8千克的并且是没有刻度的酒瓶,3千克和5千克的瓶子均装满了酒,而8千克的瓶子为空。现要求仅用这三个酒瓶将这些酒均分为两个4千克并分别装入5千克和8千克的瓶子中。
题解:
可以扩展为有n个瓶子,每个瓶子当前装了x1,x2,x3…xn的酒,每个瓶子的上限是y1,y2,…yn,目标状态是每个瓶子d1,d2,…dn,现在要从当前状态转换到目标状态
可以解读到,每个瓶子只有两种状态--要么盛满,要么空
所以当酒从x瓶子转移到y瓶的时候,只有可能是试图将酒全部到入y瓶中,这样会造成两种结果:
能盛得下-- x瓶空,y瓶的酒为原来的酒加上x瓶原来的酒。
盛不下-- x瓶的酒为原来的酒减去倒过去的那部分, y瓶满。
很显然,如果要求最短的步数,BFS是一个比较简单的办法,现在想输出所有的路径,所以考虑DFS
代码:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner; //已知有3个容量分别为3kg,5kg和8kg且没有刻度的酒瓶3kg和5kg的瓶子均装满了酒。而8kg的瓶子为空。
//现要求仅用这3个酒瓶将这些酒均分为两个4kg,并分别装入5kg和8kg的瓶子中。 public class DispensingProblem {
public static int N; //酒瓶的数量
public static Integer[] bottleMax; //每个酒瓶最多装多少酒
public static Integer[] bottleCurrent; //每个酒瓶现在装了多少酒
public static Integer[] bottleFinal; //标注每个酒瓶的最终状态
public static ArrayList<String> states; //标注每一种状态,防止重复(每一种状态是一个向量,我用整型数组表示)
public static ArrayList<String[]> paths; //标注每一条路径
public static int caseNum = 0; //标注是第几种方法
public static int minNum = 1000000; //标注最少需要的步数
public static void dfs(int n){
String testS = String.valueOf(bottleCurrent[0]);
for(int m =1;m<N;m++)
testS+=String.valueOf(bottleCurrent[m]);
boolean flag = true;
for(int k = 0;k<N;k++)
if(bottleCurrent[k]!=bottleFinal[k])
flag = false;
if(flag){
caseNum ++ ;
if(n <= minNum){
if(n<minNum){
paths.clear();
}
String[] tempS= new String[states.size()];
for(int ll = 0;ll<states.size();ll++)
tempS[ll] = states.get(ll);
paths.add(tempS);
minNum = n;
}
System.out.println("第"+caseNum+"种方法:");
for(int l=0;l<states.size();l++)
System.out.println(states.get(l));
System.out.println("总共需要移动"+n+"步");
System.out.println("------------------------------------");
return;
}
//找出当前可能的所有移动
//数据不大,不需要优化
//每个瓶子只能倒满或者倒空
//注意要标注每一种状态,防止状态重复
for(int i = 0 ; i < N;i++)
for(int j = 0; j < N ;j++){
if(i==j)
continue;
//从i瓶把所有酒倒入j瓶
int nI = bottleCurrent[i];
int nJ = bottleCurrent[j];
int temp = nI + nJ - bottleMax[j];
if(temp<=0){
//能全倒进去
bottleCurrent[i] = 0;
bottleCurrent[j] = nI + nJ;
String s = String.valueOf(bottleCurrent[0]);
for(int m =1;m<N;m++)
s+=String.valueOf(bottleCurrent[m]);
if(!states.contains(s)){
states.add(s);
dfs(n+1);
//回溯
states.remove(states.indexOf(s));
}
//回溯
bottleCurrent[i] = nI;
bottleCurrent[j] = nJ;
}
else{
//不能全倒进去
bottleCurrent[i] = temp;
bottleCurrent[j] = bottleMax[j];
String s = String.valueOf(bottleCurrent[0]);
for(int m =1;m<N;m++)
s+=String.valueOf(bottleCurrent[m]);
if(!states.contains(s)){
states.add(s);
dfs(n+1);
//回溯
states.remove(states.indexOf(s));
}
//回溯
bottleCurrent[i] = nI;
bottleCurrent[j] = nJ;
}
}
//找遍所有状态都不可行,则表明不能出现这种状态
//System.out.println("不可能存在这种状态!");
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入瓶子个数");
N = sc.nextInt();
bottleMax = new Integer[N];
bottleCurrent = new Integer[N];
bottleFinal = new Integer[N];
states = new ArrayList<String>();
paths = new ArrayList<String[]>();
System.out.println("请输入每个瓶子的容量");
for(int i = 0 ;i < N; i ++){
bottleMax[i] = sc.nextInt();
}
System.out.println("请输入每个瓶子当前有多少酒");
for(int i = 0 ;i < N; i ++){
bottleCurrent[i] = sc.nextInt();
}
System.out.println("请输入最终希望每个瓶子有多少酒");
for(int i = 0 ;i < N; i ++){
bottleFinal[i] = sc.nextInt();
}
String s = String.valueOf(bottleCurrent[0]);
for(int i =1;i<N;i++)
s+=String.valueOf(bottleCurrent[i]);
states.add(s);
dfs(0);
System.out.println("******************************");
System.out.println("最少需要"+minNum+"步");
int index = 0;
for(int i = 0;i<paths.size();i++){
index++;
System.out.println("第"+index+"种最短方法:");
String[] temp = paths.get(i);
for(int j = 0;j<temp.length;j++)
System.out.println(temp[j]);
System.out.println("-----------------------------------");
}
System.out.println("******************************");
}
}
分酒问题(DFS解法)的更多相关文章
- 算法笔记_219:泊松分酒(Java)
目录 1 问题描述 2 解决方案 1 问题描述 泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他 ...
- Java实现 泊松分酒
泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他提出过一个有趣的问题,后称为:"泊松分酒& ...
- UVALive 6450 Social Advertising DFS解法
题意:一些人有朋友关系,在某个人的社交网站上投放广告可以被所有该人的直接朋友看到,问最小投放多少个广告使给出的人都看到广告.(n<=20) 解法:看到n的范围可以想到用二进制数表示每个人被覆盖与 ...
- 分珠(dfs+并查集)
1140 分珠 时间限制:500MS 内存限制:65536K提交次数:24 通过次数:18 题型: 编程题 语言: G++;GCC Description 如下图所示,有若干珠子,每颗珠子重量不 ...
- PTA 1004 Counting Leaves (30)(30 分)(dfs或者bfs)
1004 Counting Leaves (30)(30 分) A family hierarchy is usually presented by a pedigree tree. Your job ...
- PAT 甲级 1018 Public Bike Management (30 分)(dijstra+dfs,dfs记录路径,做了两天)
1018 Public Bike Management (30 分) There is a public bike service in Hangzhou City which provides ...
- 蓝桥杯-分考场(dfs)
分考场 PREV-53 这题的解决方法使用dfs,因为数据很小,才100. 每次当前的人人是否可以和前面的组队,设置两个数组group和fri /*DFS求解:思路每次判断输入的人是否可以和前面的组队 ...
- hdu4982 Goffi and Squary Partition (DFS解法)
BestCoder Round #6 B http://acm.hdu.edu.cn/showproblem.php?pid=4982 Goffi and Squary Partition Time ...
- HDU 1312 Red and Black --- 入门搜索 DFS解法
HDU 1312 题目大意: 一个地图里面有三种元素,分别为"@",".","#",其中@为人的起始位置,"#"可以想象 ...
随机推荐
- python中with学习
python中with是非常强大的一个管理器,我个人的理解就是,我们可以通过在我们的类里面自定义enter(self)和exit(self,err_type,err_value,err_tb)这两个内 ...
- spring 内部工作机制(二)
本章节讲Spring容器从加载配置文件到创建出一个完整Bean的作业流程及参与的角色. Spring 启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表, ...
- cnblog排版
记录一些自己写博客中的排版技巧 一.标题 红色部分代码用在标题的CSS样式中 <p style="background: gray; font-size: 18px; font-fam ...
- HDU1142 A Walk Through the Forest(最短路+DAG)
A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/O ...
- commons-pool与commons-pool2连接池
commons-pool和commons-pool2是用来建立对象池的框架,提供了一些将对象池化必须要实现的接口和一些默认动作.对象池化之后可以通过pool的概念去管理其生命周期,例如对象的创建,使用 ...
- MxNet新前端Gluon模型转换到Symbol
1. 导入各种包 from mxnet import gluon from mxnet.gluon import nn import matplotlib.pyplot as plt from mxn ...
- EasyUI Dialog 窗体 布局记要
通常在窗体里放置的都是表单,或者使用分栏(Tab)来陈列信息也是非常的好用.在这里特别记录一下在窗体里同时放置表单和表格的设计思路. 仅放置一个表单 通常 Dialog 里只放一个表单,而且表单的行数 ...
- 【学习】Zepto与jQuery 差别
前几天遇到一个项目,需要把jquery全部改成Zepto,当时因为自己没有实际经验,所以没有接.今天查了一下两者究竟有什么区别. 首先看到了这么一篇文章:http://www.bootcss.com/ ...
- caffe源码 池化层 反向传播
图示池化层(前向传播) 池化层其实和卷积层有点相似,有个类似卷积核的窗口按照固定的步长在移动,每个窗口做一定的操作,按照这个操作的类型可以分为两种池化层: 输入参数如下: 输入: 1 * 3 * 4 ...
- win7下安装Ubuntu后进不去win7的解决方法
win7下安装Ubuntu后进不去win7的解决方法 刚刚给同学在win7下安装了Ubuntu16.04,结果在安装完后竟然无法在电脑重启后,找到win7的进入选项. 在网上找了找,都不行!就差点重装 ...