题目大概是这样:

已知有三个容量分别为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解法)的更多相关文章

  1. 算法笔记_219:泊松分酒(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他 ...

  2. Java实现 泊松分酒

    泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他提出过一个有趣的问题,后称为:"泊松分酒& ...

  3. UVALive 6450 Social Advertising DFS解法

    题意:一些人有朋友关系,在某个人的社交网站上投放广告可以被所有该人的直接朋友看到,问最小投放多少个广告使给出的人都看到广告.(n<=20) 解法:看到n的范围可以想到用二进制数表示每个人被覆盖与 ...

  4. 分珠(dfs+并查集)

    1140 分珠 时间限制:500MS  内存限制:65536K提交次数:24 通过次数:18 题型: 编程题   语言: G++;GCC Description 如下图所示,有若干珠子,每颗珠子重量不 ...

  5. 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 ...

  6. 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 ...

  7. 蓝桥杯-分考场(dfs)

    分考场 PREV-53 这题的解决方法使用dfs,因为数据很小,才100. 每次当前的人人是否可以和前面的组队,设置两个数组group和fri /*DFS求解:思路每次判断输入的人是否可以和前面的组队 ...

  8. hdu4982 Goffi and Squary Partition (DFS解法)

    BestCoder Round #6 B http://acm.hdu.edu.cn/showproblem.php?pid=4982 Goffi and Squary Partition Time ...

  9. HDU 1312 Red and Black --- 入门搜索 DFS解法

    HDU 1312 题目大意: 一个地图里面有三种元素,分别为"@",".","#",其中@为人的起始位置,"#"可以想象 ...

随机推荐

  1. MySQL所学所思所想

    MySQL更改线上配置方案思想:原则上,需要备机.备份工作准备到位,有参数调优配置方案.有配置回退方案.有应急切换备机方案.以上方案评审无问题,然后可以和客户约定实施的时间.服务中断时间,先向客户侧申 ...

  2. Codeforces Round #425 (Div. 2)C

    题目连接:http://codeforces.com/contest/832/problem/C C. Strange Radiation time limit per test 3 seconds ...

  3. Crossin 8-3;8-4

    8-3文件打开模式:r:只读模式.默认w:只写模式.会先清空文件a:追加写入模式,在文件末尾写入,不可读r+:打开一个文件用于读写.文件指针将会放在文件的开头,原文件内容不会清空b:二进制模式,与前面 ...

  4. 【转】 文档与笔记利器 reStructuredText 和 Sphinx

    关于制作文档和笔记这种事,我已经纠结了很久,网上解决方案也一大推,我试过几样,ScrapBook 和 Zotero,编辑不太方便,同步麻烦.Google Note 过于格式简单,现在也不更新了,Goo ...

  5. 用C#实现字符串相似度算法(编辑距离算法 Levenshtein Distance)

    在搞验证码识别的时候需要比较字符代码的相似度用到"编辑距离算法",关于原理和C#实现做个记录. 据百度百科介绍: 编辑距离,又称Levenshtein距离(也叫做Edit Dist ...

  6. 我修改的时钟flash

    <object type="application/x-shockwave-flash" style="outline:none;" data=" ...

  7. java中==与equel的区别

    值类型是存储在内存中的堆栈(以后简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中. ==操作比较的是两个变量的值是否相等,对于引用型变量表示的是两个变量在堆中存储的地 ...

  8. Linux 进程状态 概念 Process State Definition

    From : http://www.linfo.org/process_state.html 进程状态是指在进程描述符中状态位的值. 进程,也可被称为任务,是指一个程序运行的实例. 一个进程描述符是一 ...

  9. 使用Java 8中的Stream

    Stream是Java 8 提供的高效操作集合类(Collection)数据的API. 1. 从Iterator到Stream 有一个字符串的list,要统计其中长度大于7的字符串的数量,用迭代来实现 ...

  10. C 结构体零散知识点

    1.结构体无法把自己作为成员,但可以包含指向自己的指针成员 2.定义不完整结构类型(类型,结构,占用空间无法确定,如void指针,声明没有指明数组长度数组)只能使用小标签,即struct struct ...