算法题:水杯倒水的问题

之前好像在博客园看到这样的题目:

1.有3个容器,各是20升,13升,7升, 形状不同也不透明。一开始20升的容器里面装了20升水,反正倒来倒去最后要让20升和13升容器各装了10升水

2. 2个外形不同的瓶子,各装800毫升水,另外还有1个300毫升的杯子

现在有4个人,不限制喝的次数,想办法让每个人都正好喝到400毫升水

第一第二道题目,口头说明解法就行了 
第三个题,就是从第一第二题里面随便选择一个,使用编程来求解

于是乎..觉得有趣.便做了起来...花了一个下午的时间..终于做出来了:

首先建了一个水杯类: //以下程序只是基于可运行..至于代码的可看性和性能,暂时还没做优化
   public class Cut
    {
        private int _maxValue;//杯子的最大值
        public int MaxValue
        {
            get
            {
                return _maxValue;
            }
        }
        private int _currentValue;//杯子当前值
        public int CurrentValue
        {
            get
            {
                return _currentValue;
            }
            set
            {
                _currentValue = value;
            }
        }

        public Cut(int maxValue,int currentValue)
        {
            _maxValue = maxValue;
            _currentValue = currentValue;
        }
    }
然后在控制台程序环境下:
 class Program
    {
        private static List<int[]> valueList = new List<int[]>();//用于记录正确的步骤
        private static int[] values = new int[3];//当前的步骤
        private static Cut c7 = new Cut(7, 0);
        private static Cut c13 = new Cut(13, 0);
        private static Cut c20 = new Cut(20, 20);
        static void Main(string[] args)
        {
            valueList.Clear();
            ChangeCut(ref c7, ref c13, ref c20);
        }
        static bool GetDirection(int[] currentValues)//true表示可以继续下一次[节点不存在],false则反之[表示节点存在]
        {
            if (valueList.Count == 0)//第一次时.不存在重复节点,返回真
            {
                return true;
            }
            int count = 0;
            for (int i = 0; i < valueList.Count; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    if (valueList[i][j] == currentValues[j])//只要发现不相等,转入下一个
                    {
                        count++;
                        if (count == 3)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        count = 0;
                        break;

                    }
                }
            }
            return true;

        }
        static void ChangeCut(ref Cut c1, ref Cut c2, ref Cut c3)
        {
            Cut cutA = c2;//第一次交换的值
            Cut cutB = c3;;//第一次交换的值
            while (true)
            {
                if (!ChangeTwoCut(ref cutA, ref cutB))//交换两个杯的值
                {
                    valueList.RemoveAt(valueList.Count - 1);//交换失败时.删除最后一个节点
                    c7.CurrentValue = valueList[valueList.Count - 1][0];//退回上一节点的值
                    c13.CurrentValue = valueList[valueList.Count - 1][1];//退回上一节点的值
                    c20.CurrentValue = valueList[valueList.Count - 1][2];//退回上一节点的值

                }
                RadomCut(ref c1, ref c2, ref c3, out cutA, out cutB);//随机取两个杯交换
            }
        }
        static void RadomCut(ref Cut c1, ref Cut c2, ref Cut c3, out  Cut c11, out Cut c12)//随机产生两个杯
        {
            Random rd = new Random();
            int result = rd.Next(3);
            if (result == 0)
            {
                c11 = c1;
            }
            else if (result == 1)
            {
                c11 = c2;
            }
            else
            {
                c11 = c3;
            }
            int result2 = rd.Next(3);
            while (result2 == result)//用于产生不和上面重复的值
            {
                result2 = rd.Next(2);
            }
            if (result2 == 0)
            {
                c12 = c1;
            }
            else if (result2 == 1)
            {
                c12 = c2;
            }
            else
            {
                c12 = c3;
            }
        }
        static bool ChangeTwoCut(ref Cut c1, ref Cut c2)
        {
            bool result = false;
            int valueA;
            int valueB;
            int tempA = c1.CurrentValue;
            int tempB = c2.CurrentValue;
          //默认先走左边
            GetChangedValue(c1, c2, out valueA, out valueB, true);//两个杯交换后的值
            c1.CurrentValue = valueA;
            c2.CurrentValue = valueB;
            if (GetDirection(new int[] { c7.CurrentValue, c13.CurrentValue, c20.CurrentValue }))
            {
                result = true;
            }
            else  //走右边
            {
                GetChangedValue(c1, c2, out valueA, out valueB, false);
                c1.CurrentValue = valueA;
                c2.CurrentValue = valueB;
                if (GetDirection(new int[] { c7.CurrentValue, c13.CurrentValue, c20.CurrentValue }))
                {
                    result = true;
                }
            }
            if (result)
            {
                GetResult();
            }
            else //失败,还原值
            {
                c1.CurrentValue = tempA;
                c2.CurrentValue = tempB;
            }
            return result;
        }
        static void GetChangedValue(Cut c1, Cut c2, out int valueA, out int valueB, bool AtoB)//两种情况,一种A的值给B,一种B的值给A
        {
            int maxValue = c1.CurrentValue + c2.CurrentValue;
            //边界测定
            if (c1.CurrentValue == 0)
            {
                valueA = c2.CurrentValue > c1.MaxValue ? c1.MaxValue : maxValue;
                valueB = maxValue - valueA;
            }
            else if (c1.CurrentValue == c1.MaxValue)
            {
                int need = c2.MaxValue - c2.CurrentValue;
                if (c1.CurrentValue >= need)
                {
                    valueA = c1.CurrentValue - need;
                    valueB = c2.CurrentValue + need;
                }
                else
                {
                    valueA = 0;
                    valueB = maxValue;
                }
            }
            else if (c2.CurrentValue == 0)
            {
                valueB = c1.CurrentValue > c2.MaxValue ? c2.MaxValue : maxValue;
                valueA = maxValue - valueB;
            }
            else if (c2.CurrentValue == c2.MaxValue)
            {
                int need = c1.MaxValue - c1.CurrentValue;
                if (c2.CurrentValue > need)
                {
                    valueA = c1.CurrentValue + need;
                    valueB = c2.CurrentValue - need;
                }
                else
                {
                    valueA = maxValue;
                    valueB = 0;
                }
            }
            else //非边界值时
            {
                if (AtoB)//A的值给B时
                {
                    valueB = maxValue > c2.MaxValue ? c2.MaxValue : maxValue;
                    valueA = maxValue - valueB;
                }
                else//B的值给A时
                {
                    valueA = maxValue > c1.MaxValue ? c1.MaxValue : maxValue;
                    valueB = maxValue - valueA;
                }
            }
        }

        static void GetResult() //添加正确步骤或显示结果
        {
            if (c20.CurrentValue == 10 || c13.CurrentValue == 10)
            {
                int[] newValue = new int[3] { c7.CurrentValue, c13.CurrentValue, c20.CurrentValue };
                valueList.Add(newValue);
                Console.WriteLine("结果已出如下:");
                for (int i = 0; i < valueList.Count; i++)
                {
                    Console.WriteLine("第" + i.ToString() + "步: " + valueList[i][0].ToString() + ":" + valueList[i][1].ToString() + ":" + valueList[i][2].ToString());
                }
                Console.ReadLine();
            }
            else
            {
                int[] newValue = new int[3] { c7.CurrentValue, c13.CurrentValue, c20.CurrentValue };
                valueList.Add(newValue);
                Console.WriteLine(newValue[0].ToString() + ":" + newValue[1].ToString() + ":" + newValue[2].ToString());
            }
        }
    }

时间: 2024-08-30 18:48:57

算法题:水杯倒水的问题的相关文章

一个算法题,求答案啊啊啊啊

问题描述 一个算法题,求答案啊啊啊啊 白班 09:00-18:00 通班 09:00-21:00 每个人每个月通班数量必须等于早中班和中晚班数量之和 早中班 09:00-15:00 中晚班 15:00-21:00 假设:每月按照30计算. 排班规则: 1.每个人每个月固定休息6天连续上班天数不超过7天. 2.每天各班次上班的人数最低需求:8个白班5个通班1个早中班,2个中晚班. 3.每个月每个人的通班天数安排不超过8天. 4.每个人每个月早中班和中晚班的天数之和需要与通班天数相等. 5.每月最多

算法题:把阿拉伯金额转化为汉字表示的金额

n年没写算法题了,今天用了20分钟写了一个,要求如题,感觉算法有所退步,老了 using System; using System.Text; namespace money { class Program { static void Main(string[] args) { StringBuilder sb=new StringBuilder(); var strValue = Console.ReadLine(); var strlist = strValue.Split('.'); if

算法题:poj 2541 Binary Witch(KMP水过,逆序转换)

链接: http://poj.org/problem?id=2541 分析与总结: 做这题估算了下复杂度,觉得无论KMP再怎么快,这题暴力也肯定要超时的. 想了很久也没想出个好办法,于是决定暴力之,但是TLE了....于是就放了几天.之后看了下discuss ,这题的正解应该是状态压缩dp,不过目前我还不懂,跪了. 之后百度发现也可以用KMP水过,虽然是因为数据水才过的,不过这种思路很巧妙,值得借鉴! 直接暴力是枚举字符串的后面13个的字母,然后再用KMP匹配,这样的话,就绪要枚举多次,分别是

算法题:HDU 2594 Simpsons’ Hidden Talents(KMP)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=2594 题目大意: 给两个字符串s1和s2, 求出是s1的前缀并且是s2的后缀的最长的字符串. 分析与总结: 真正理解好KMP算法,这题就是水题. 首先求出s1的失配函数,然后在s2中 寻找s1字符串. 在寻找字符串过程中,会有一个状态值j,这个值表示的是当前在s2中已经匹配 了多少个s1的字符. 所以,全部匹配完后,最后j的值就是以s2的最后一个字符结尾,和s1的前缀相匹 配的最长字符串.也就是所求的

算法题:uva 10318

题目链接: 首先,可以确定每个格子只能选一次,因为选任何大于0的偶数次,等于没有效果 一样. 然后,就可以把这题理解成从r*c的矩阵中选择一些格子进行"点亮"操作,使得最终所 有格子都是"亮"的状态.那么,每个格子要么有点亮操作,要么没有,总共复杂度为2^25,显然必须 进行减枝. 假设从第一行第一列开始,从左往右,从上往下一次依次选择,对于当前所在位置( x, y),它已经不能影响到x-2以前的行数了,所以当到x行时,如果第x-2行没有全部点亮,则进行减枝 . 此

算法题:uva 1330

题目链接: http://uva.onlinejudge.org/index.php? option=com_onlinejudge&Itemid=8&category=460&page=show_problem&problem=4076 以前做过一道一维的,这题只是变成了二维的,其他方法都一样.HDU 1506  Largest Rectangle in a Histogram   题解 代码1: #include<cstdio> #include<cs

求一个面试算法题答案。

问题描述 求一个面试算法题答案. 已知函数f()以相同的概率返回0或者1,求一个函数g()以相同的概率返回0-7之间的任意一个数字. 解决方案 其实这个题不难,可以考虑用2进制的方式来做.g(){return 4*f()+2*f()+f();} 希望能帮到你. 解决方案二: #includeint g(){srand(time(NULL));ret = rand()%8;return ret;}

经典算法题每日演练——第七题 KMP算法

原文:经典算法题每日演练--第七题 KMP算法       在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输 入法总是提示"看毛片"三个字,嘿嘿,就叫"看毛片算法"吧. 一:BF算法      如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知

java算法题,公司的笔试题

问题描述 java算法题,公司的笔试题 suppose you have N cakes, N is an interger>0 // at each time, you can either eat 1 cake, or 2 cakes or 3 cakes // PROBLEM: How many ways can you eat all N cakes // for example, N = 4, (1,2,1) and (1,1,2) are considered to be diffe