面试遇到的算法题:两个杯子量水

diyuhou 2010-11-16 08:10:56
2个杯子 容积分别为a和b (int型 大于0) 想用这两个杯子称出c升水(c也是int型 大于0)
要求 a b c全部由用户输入 然后写出每一步的详细情况 并且 每一步只能动一个杯子
比如 a=1 b=2 要求称3升水 步骤为
1,0
1,2
每次只能给一个杯子装水(即不能直接输出1,2) 倒水也一样
最后再屏幕上输出这些步骤 要求是最简步骤

这个算法 怎么做哇......有什么思路么......
...全文
1430 49 打赏 收藏 转发到动态 举报
写回复
用AI写文章
49 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
我在41楼给出的三个杯子的规划结果是一个可行的操作步骤,但是其实用眼睛“运行”几步就会发现算法的问题,我没有随机选择3个杯子中的一个而是顺序选择,并且对于可行的操作没有随机打乱次序去尝试而是按照“倒满、倒空、顺序选择其它杯子并倒水”这样的僵化的次序、而非启发的次序去查找。但是因为我强调了最基本的要求、结构、算法,如果连方向都错了,根本不顾实际题目要打印出操作次序这个前提,那么我也没有必要写出程序来说明“人工智能搜索程序”到底是个什么模式的,那么这个面试题目也就失败了,这个题目没有面试到程序员反而面试到数学家了。
whrspsoft3723 2010-11-17
  • 打赏
  • 举报
回复
还是贴个完整版吧。 不知是否有漏洞,请大家指正。

void test(int a, int b, int c) {
//swap a,b resut = a > b
if(a < b){
int k = b;
b = a;
a = k;
}

int m = 1,n = 0;

if (c % a == 0 || c % b == 0) {
Debug("OK");
return;
}

// n = 1, m >= 1
m = 1;
while (c > m * a - b) {
if (c % (m * a - b) == 0) {
Debug(string.Format("{0} * {1} - {}2",m,a,b));
return;
}

m++;
}


//m = 1,n >= 1
n = 1;
while (c > a - n*b && a - n*b > 0) {
if (c % (a - n*b) == 0) {
Debug(string.Format("{0} - {1} * {2}",a,n,b));
return;
}
n++;
}

//-------------------------
// m = 1,n >= 1
n = 1;
while (c > a + n*b) {
if (c % (a + n*b) == 0) {
Debug(string.Format("a + n*b = {0} + {1}* {2}",a,n,b));
return;
}

n++;
}

//3 n = 1, m >= 1
m = 1;
while (c > m*a + b ) {
if (c % (m*a + b) == 0) {
Debug(string.Format("m*a + b = {0}*{1} + {2}",m,a,b));
return;
}
m++;
}

Debug("无解");
}

void Debug(string s) {
MessageBox.Show(s);
}

  • 打赏
  • 举报
回复
不但知道做什么而且尤其知道怎么做(给出规划结果可以让不懂数学的人去验证),要比纯粹论证,重要多了。
whrspsoft3723 2010-11-17
  • 打赏
  • 举报
回复


//-------------------------
// m = 1,n >= 1
n = 1;
while (c > a + n*b) {
if (c % (a + n*b) == 0) {
Debug(string.Format("a + n*b = {0} + {1}* {2}",a,n,b));
return;
}

n++;
}




还是有个地方错了, 用这个替换 。
  • 打赏
  • 举报
回复
“人工智能”的前提首先是真实,凡是真实的但是不容易用人来规划的都可以算作人工智能。如果给出一堆数学公式,给过无法用不懂数学的普通人所理解的话把答案说出来,那么当然只能回避“智能”这个要求。

如果不能给出普通人都懂的真实语言描述,那么玩数学、程序有什么现实的意思?
binadan 2010-11-17
  • 打赏
  • 举报
回复
可以试想有3个容器A B 和C
C是假想的无穷大的容器
杯子的属性: 容积 水量 剩余容积
方法 从杯子x向杯子y倒入z升的水
我的思路 数据库 表 存储过程/函数 递归 事务
回滚条件:出现已出现过的杯子存水状态,
终止条件:出现解/杯子1所有操作都递归过

whrspsoft3723 2010-11-17
  • 打赏
  • 举报
回复

void test(int a, int b, int c) {
//swap a,b resut = a > b
if(a < b){
int k = b;
b = a;
a = k;
}

int m = 1,n = 0;

if (c % a == 0 || c % b == 0) {
Debug("OK");
return;
}

// n = 1, m >= 1
m = 1;
while (c > m * a - b) {
if (c % (m * a - b) == 0) {
Debug(string.Format("{0} * {1} - {}2",m,a,b));
return;
}

m++;
}


//m = 1,n >= 1
n = 1;
while (c > a - n*b && a - n*b > 0) {
if (c % (a - n*b) == 0) {
Debug(string.Format("{0} - {1} * {2}",a,n,b));
return;
}
n++;
}

//-------------------------
// m = 1,n >= 1
n = 1;
while (c > a - n*b) {
if (c % (a - n*b) == 0) {
Debug(string.Format("a - n*b = {0} - {1}* {2}",a,n,b));
return;
}

n++;
}

//3 n = 1, m >= 1
m = 1;
while (c > m*a + b ) {
if (c % (m*a + b) == 0) {
Debug(string.Format("m*a + b = {0}*{1} + {2}",m,a,b));
return;
}
m++;
}

Debug("无解");
}



void Debug(string s) {
MessageBox.Show(s);
}



这个应该可以了, 只是没有打印出来过程。
在循环中加入debug
debug()重载成输出,就应该可以了。

  • 打赏
  • 举报
回复
唉,只说空的没意思。比如出这样一个题目,三个杯子分别有3升、7升,20升,要求量出11升水来,如何找出一个相对快的倒法?

必须打印出操作步骤,弄数学公式是无法实际去操作的(比如产生指令,或者让人容易地看出对错)。

比如我打印一个倒法:

倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
从3升杯子向7升杯子倒水
倒满3升杯子
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
倒空3升杯子
从7升杯子向3升杯子倒水
从3升杯子向20升杯子倒水
绿色夹克衫 2010-11-17
  • 打赏
  • 举报
回复
3个以上的杯子用DP可以,前提是C不能太大,100万以内的话可以,实际上是一个背包问题,也是算法问题,还不涉及“智能”

[Quote=引用 37 楼 sp1234 的回复:]

其实这个题目出的缺乏“智能”,如果给3个以上的杯子,才能体现一些智能特点。
[/Quote]
wdzr_826 2010-11-17
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 sp1234 的回复:]

引用 34 楼 microtry 的回复:
看见楼主的题目,感觉自己变NC了,
A=30;
B=70;
C=2;
仅仅在脑海里输入这3个参数,我都无法得出答案,别说编程了


故意加个0就过分了。3、7、2能不能口算得出答案?
[/Quote]
30.70.2肯定是没答案的。
3.7.2
那3升的一致往7升的里面倒,倒满7升的,3升里面剩两胜
  • 打赏
  • 举报
回复
其实这个题目出的缺乏“智能”,如果给3个以上的杯子,才能体现一些智能特点。
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 microtry 的回复:]
看见楼主的题目,感觉自己变NC了,
A=30;
B=70;
C=2;
仅仅在脑海里输入这3个参数,我都无法得出答案,别说编程了
[/Quote]

故意加个0就过分了。3、7、2能不能口算得出答案?
  • 打赏
  • 举报
回复
[Quote=引用 34 楼 microtry 的回复:]
看见楼主的题目,感觉自己变NC了,
A=30;
B=70;
C=2;
仅仅在脑海里输入这3个参数,我都无法得出答案,别说编程了
[/Quote]

30、70、2?
缪军 2010-11-17
  • 打赏
  • 举报
回复
看见楼主的题目,感觉自己变NC了,
A=30;
B=70;
C=2;
仅仅在脑海里输入这3个参数,我都无法得出答案,别说编程了
zhubo006 2010-11-17
  • 打赏
  • 举报
回复
nmjyxl 2010-11-17
  • 打赏
  • 举报
回复
学习了
达不溜来多多 2010-11-17
  • 打赏
  • 举报
回复
有人去给我的那个问题随便回贴吗 我结贴50分
绿色夹克衫 2010-11-17
  • 打赏
  • 举报
回复
to:sp1234牛

您把问题弄复杂了,按照LZ原题的要求,我的程序只输出了“奇怪的数学公式”,比如58 = 5 * 11 + 3(5和3是杯子的容量),但这个真的很难理解么?讨论算法点到为止即可,我只是说这个算法的思路,并不是要替LZ写出具体程序。如果真的按照ACM的标准,您给出的输出同样是不合标准的,LZ要求的是:

1,0
1,2

况且您真的认为您给出的那么长的序列会比我给出的“奇怪的数学公式”更好验证么?

不要说3个杯子,就是100个杯子,求最优都可以用动态规划来解(DP),只要C不是很大,都可以在内存中完成计算。这只是一个入门级的算法题,相信里人工智能还有很远的距离,最多也就是考察一下算法设计者的“智能”。可以放心的是,绝对不会惊动到数学家的,像我这样的小程序员就可以搞定。

作为程序员讨论这个算法,我可以说,用欧几里得扩展的方法,时间复杂度是O(Log(n))的,用动态规划的方法,时间复杂度要高很多,是O(m*n)的,其中n是c取值的范围,m是杯子的个数。以上两个程序都可以在100行代码以内解决问题,绝不是什么高科技。而您所提到的“人工智能搜索”,复杂度如何呢?
showjim 2010-11-17
  • 打赏
  • 举报
回复
看了这个贴子,有一个感慨:软件与算法什么时候变得不相干了?
绿色夹克衫 2010-11-17
  • 打赏
  • 举报
回复
果然有bug,发现了,顺便改成了long,自己再测测!

using System;

namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
int a = 1597, b = 2584, c = 198787;
long countA, countB;

int gcd = EuclidExtend(a, b, out countA, out countB);
int K = c / gcd;

if (c != K * gcd)
{
Console.WriteLine("无解");
return;
}

countA *= K; countB *= K; a /= gcd; b /= gcd;

int temp = a > b ? (int)Math.Abs(countB / a) : (int)Math.Abs(countA / b);
int flag = countA < 0 ? 1 : -1;
long minA = 0, minB = 0, minSum = int.MaxValue;

for (int i = temp - 1; i <= temp + 1; i++)
{
long sum = Math.Abs(countA + (i * b) * flag) + Math.Abs(countB - (i * a) * flag);
if (sum < minSum)
{
minA = countA + (i * b) * flag;
minB = countB - (i * a) * flag;
minSum = sum;
}
}

Console.WriteLine("{0} = ({1}*{2}) + ({3}*{4})", c, a * gcd, minA, b * gcd, minB);
}

public static int EuclidExtend(int X, int Y, out long A, out long B)
{
if (Y == 0) { A = 1; B = 0; return X; }

int quotient = X / Y;
int gcd = EuclidExtend(Y, X - Y * quotient, out A, out B);

long Temp = A; A = B; B = Temp - quotient * A;
return gcd;
}
}
}
加载更多回复(28)

111,125

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧