百度之星,是全球最大的中文搜索引擎,百度公司面向中国高校学生和编程爱好者所举办的高水平的程序设计大赛。他所考试的题目,全部都是算法的题目。
鄙人虽然是一个.net程序员,在工作之余,喜爱算法。 这个问题与现实的需求蛮贴近,故而分享给大家,我想到两种方法,提供大家,希望对大家起了一个开阔思路的作用。
首先,题意是这样的:
1 饭团的烦恼 2 3 “午餐饭团“是百度内部参与人数最多的民间组织。 4 5 同一个部门的,同一间大学的,同一年出生的,用同一种型号电脑的,员工们总是以各种理由,各种借口组织各种长久的,临时的饭团。 6 7 参加饭团,不仅可以以优惠的价格尝到更加丰富的菜式,还可以在吃饭的时候和同事们唠唠嗑,吹吹水,增进感情。 8 9 但是,随着百度的员工越来越多,各个饭团的管理随即变得烦杂。特别是为了照顾员工们越来越挑剔的胃口,饭团的点菜负责人背负的责任越来越大。现在,这个重担落在百度之星的肩上,因为,你们将要为所有的百度饭团设计一个自动点菜的算法。 10 11 饭团点菜的需求如下: 12 13 1. 经济是我们要考虑的一个因素,既要充分利用百度员工的午餐补助,又不能铺张浪费。因此,我们希 14 15 望最后的人均费用越接近 12 元越好。 16 17 2. 菜式丰富是我们要考虑的另一个因素。为简单起见,我们将各种菜肴的属性归结为荤菜,素菜,辛辣, 18 清淡,并且每个菜只能点一次。 19 20 3. 请紧记,百度饭团在各大餐馆享受 8 折优惠。 21 22 输入数据描述如下: 23 24 第一行包含三个整数 N,M,K(0<=16,0=16,0<=N,0 25 需要点的菜的数目,就餐的人数。 =12),分别表示菜单上菜的数目,饭团需要点的菜的数目,就餐的 26 人数。 27 28 紧接着 N 行,每行的格式如下: 29 30 菜名(长度不超过 20 个字符) 价格(原价,整数) 是否荤菜(1 表示是,0 表示否) 是否辛辣(1 表示 31 是,0 表示否)例: 32 33 水煮鱼 30 1 1 34 35 紧接着是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清淡菜的数目。 36 37 输出数据: 38 39 对于每一测试数据,输出数据包含 M+1 行,前 M 行每行包含一个菜名(按菜名在原菜单的顺序排序)。第 40 M+1 行是人均消费,结果保留两位小数。 41 42 说明: 43 44 1.结果菜单的数目应该恰好为 M,荤菜,素菜,辛辣,清淡菜的数目恰好为 a,b,c,d。在满足这样的 45 前提下,选择人均消费最接近 12 元的点菜方案。题目数据保证有且仅有一个解。 46 47 2.每组测试数据的结果用一个空行隔开。末尾不要有多余的空行。 48 49 输入样例 50 51 3 2 2 52 53 水煮鱼 30 1 54 55 1 口水鸡 18 1 1 56 57 清炖豆腐 12 0 0 58 59 望最后的人均费用越接近 12 元越好。 60 61 2. 菜式丰富是我们要考虑的另一个因素。为简单起见,我们将各种菜肴的属性归结为荤菜,素菜,辛辣, 62 清淡,并且每个菜只能点一次。 63 64 3. 请紧记,百度饭团在各大餐馆享受 8 折优惠。 65 66 输入数据描述如下: 67 68 第一行包含三个整数 N,M,K(0<=16,0 69 需要点的菜的数目,就餐的人数。 =12),分别表示菜单上菜的数目,饭团需要点的菜的数目,就餐的 70 人数。 71 72 紧接着 N 行,每行的格式如下: 73 74 菜名(长度不超过 20 个字符) 价格(原价,整数) 是否荤菜(1 表示是,0 表示否) 是否辛辣(1 表示 75 是,0 表示否)例: 76 77 水煮鱼 30 1 1 78 79 紧接着是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清淡菜的数目。 80 81 输出数据: 82 83 对于每一测试数据,输出数据包含 M+1 行,前 M 行每行包含一个菜名(按菜名在原菜单的顺序排序)。第 84 M+1 行是人均消费,结果保留两位小数。 85 86 说明: 87 88 1.结果菜单的数目应该恰好为 M,荤菜,素菜,辛辣,清淡菜的数目恰好为 a,b,c,d。在满足这样的 89 前提下,选择人均消费最接近 12 元的点菜方案。题目数据保证有且仅有一个解。 90 91 2.每组测试数据的结果用一个空行隔开。末尾不要有多余的空行。 92 93 输入样例 94 95 3 2 2 96 97 水煮鱼 30 1 98 99 1 口水鸡 18 1 1 100 101 清炖豆腐 12 0 0 102 103 1 1 1 1 104 105 输出样例 106 107 口水鸡 108 109 清炖豆腐 110 111 12.00 112 113 时间要求:1S 之内
题意很长了,这么从头到尾看下来的话,令人非常的头大。我们这里用图来梳理一下相应的头绪:
那么,怎么思考这个问题了。一 在输入的情况下,我要使她的每个的菜名的字符的长度不能大于20的判断 二 输入的荤菜数 素菜数 等等 要符合输入数的总数目 三为了使其满足人均消费接近12元的目标,我这里就吧他符合点菜的每个数目的具体情况用一个键值对来保存起来,其中相应的人均消费的数目做键,而相应的点菜的情况做值。四 把比较该键值对的最小值。相应的流程图如图所示:
有了思路了,我们来看一看看他的具体的实现了.
①为了实现题意,我们需要一个菜的类相应的源代码如下:
1 public class Cai 2 { 3 //名称 4 private string _CName; 5 public string CName 6 { 7 get { return _CName; } 8 set { _CName = value; } 9 } 10 //价格 11 public int CPrice { get; set; } 12 //是否是荤菜 13 public bool ISMeat { get; set; } 14 //是否是辣菜 15 public bool IsHot { get; set; } 16 }
实现逻辑的源代码如下:
1 //输入具体的需求的要求 2 Console.WriteLine( 3 @"第一行包含三个整数 N,M,K(0<=16,04 紧接着 N 行,每行的格式如下: 5 菜名(长度不超过 20 个字符) 价格(原价,整数) 是否荤菜(1 表示是,0 表示否) 是否辛辣(1 表示 6 是,0 表示否)例: 水煮鱼 30 1 1 7 紧接着是 a b c d 四个整数,分别表示需要点的荤菜,素菜,辛辣,清"); 8 Console.WriteLine(@" 9 请输入 10 (形如格式) 11 3 2 2 "); 12 //解析字符串的方法 13 string infos = Console.ReadLine(); 14 int number1 = Convert.ToInt32(infos.Split(' ')[0]); 15 int number2 = Convert.ToInt32(infos.Split(' ')[1]); 16 int number3 = Convert.ToInt32(infos.Split(' ')[2]); 17 //记录相应的菜类的泛型数组 18 List caisMeat = new List (); 19 List caisNMeat=new List (); 20 List caisHot=new List (); 21 List caisNHot=new List (); 22 //记录比较的数组 23 Dictionary<double,List > lists = new Dictionary<double, List >(); 24 int countmeat = 0; 25 int countnmeat = 0; 26 int counthot = 0; 27 int countnhot = 0; 28 //紧接着输入相应的菜数 ① 29 for (int i = 0; i < number1; i++) 30 { 31 Cai cai = new Cai(); 32 Console.WriteLine(@"请输入格式形式 33 口水鸡(小于20个字) 30(价格 整数) 1(是否浑 1是 0否) 1(是否辣 1是 0否)"); 34 infos = Console.ReadLine(); 35 36 string name = infos.Split(' ')[0]; 37 string price = infos.Split(' ')[1]; 38 string IsMeat = infos.Split(' ')[2]; 39 string IsHot = infos.Split(' ')[3]; 40 if (name.Length < 20) 41 { 42 cai.CName = name; 43 } 44 else 45 { 46 i--; 47 continue; 48 } 49 int result; 50 if (int.TryParse(price, out result)) 51 { 52 cai.CPrice = Convert.ToInt32(price); 53 } 54 else 55 { 56 i--; 57 continue; 58 59 } 60 if (IsMeat == "1") 61 { 62 cai.ISMeat = true; 63 caisMeat.Add(cai); 64 countmeat++; 65 } 66 else if (IsMeat == "0") 67 { 68 cai.ISMeat = false; 69 caisNMeat.Add(cai); 70 countnmeat++; 71 } 72 else 73 { 74 i--; 75 continue; 76 77 } 78 if (IsHot == "1") 79 { 80 cai.IsHot = true; 81 caisHot.Add(cai); 82 counthot++; 83 } 84 else if (IsHot == "0") 85 { 86 cai.IsHot = false; 87 caisNHot.Add(cai); 88 countnhot++; 89 } 90 else 91 { 92 i--; 93 continue; 94 95 } 96 } 97 Console.WriteLine("请你输入你的格式为:"); 98 Console.WriteLine("1(荤菜) 1(素菜) 1(清单菜) 1(辣菜) "); 99 int numbermeat = 0; 100 int numbernmeat = 0; 101 int numberhot = 0; 102 int numbernhot = 0; 103 104 105 //判断输入的菜品和菜的数目是否是合法的 ② 106 while (true) 107 { 108 infos = Console.ReadLine(); 109 numbermeat = Convert.ToInt32(infos.Split(' ')[0]); 110 numbernmeat = Convert.ToInt32(infos.Split(' ')[1]); 111 numberhot = Convert.ToInt32(infos.Split(' ')[2]); 112 numbernhot = Convert.ToInt32(infos.Split(' ')[3]); 113 if (numbermeat>number2) 114 { 115 Console.WriteLine("你以前输入的荤菜大于所有的定菜"); 116 continue; 117 } 118 else if (numbermeat > countmeat) 119 { 120 Console.WriteLine("你以前输入的荤菜大于所有的荤菜"); 121 continue; 122 } 123 else if (numbernmeat>number2) 124 { 125 Console.WriteLine("你以前输入的素菜大于所有的定菜"); 126 continue; 127 } 128 else if (numbernmeat > countnmeat) 129 { 130 Console.WriteLine("你以前输入的素菜菜大于所有的素菜"); 131 continue; 132 } 133 else if (numberhot>number2) 134 { 135 Console.WriteLine("你以前输入的辣菜大于所有的定菜"); 136 continue; 137 } 138 else if (numberhot>counthot) 139 { 140 Console.WriteLine("你以前输入的辣菜大于所有的辣菜"); 141 continue; 142 } 143 else if (numbernhot > number2) 144 { 145 Console.WriteLine("你以前输入的清淡菜菜大于所有的定菜"); 146 continue; 147 } 148 else if (numbernhot > countnhot) 149 { 150 Console.WriteLine("你以前输入的清淡菜大于所有的清淡菜"); 151 continue; 152 } 153 else 154 { 155 break; 156 } 157 } 158 159 int sum = 0; 160 List temps = new List (); 161 List temp1=new List (); 162 //判断了某个条件的样式的搭配 来放入到键值对中去③ 163 for (int i = 0; i <=number1-counthot; i++) 164 { 165 166 167 for (int j = 0; j <=number1-countnhot; j++) 168 { 169 170 for (int k = 0; k <= number1-countnmeat; k++) 171 { 172 173 for (int l = 0; l <= number1-countmeat; l++) 174 { 175 temps=new List (); 176 temps.AddRange(caisHot.Where(p => p.IsHot == true).OrderBy(p => p.CPrice).Skip(i).Take(numberhot).ToList()); 177 temps.AddRange(caisNHot.Where(p => p.IsHot == false).OrderBy(p => p.CPrice).Skip(j).Take(numbernhot).ToList()); 178 temps.AddRange(caisNMeat.Where(p => p.ISMeat == false).OrderBy(p => p.CPrice).Skip(k).Take(numbernmeat).ToList()); 179 180 temps.AddRange(caisMeat.Where(p => p.ISMeat == true).OrderBy(p => p.CPrice).Skip(l).Take(numbermeat).ToList()); 181 182 temps = temps.Distinct().ToList(); 183 if (!lists.Keys.Contains(temps.Sum(p => p.CPrice) * 0.8 / number3)) 184 { 185 temp1 = temps; 186 187 lists.Add(Convert.ToDouble(temps.Sum(p => p.CPrice))*0.8/number3, temp1); 188 } 189 190 } 191 } 192 } 193 } 194 //找出最接近人均12元的 菜品的搭配④ 195 double min = Math.Abs(lists.Keys.First()-12); 196 double keys = lists.Keys.First(); 197 foreach (var list in lists.Keys) 198 { 199 if (Math.Abs(list-12)<min) 200 { 201 min = Math.Abs(list - 12); 202 keys = list; 203 } 204 } 205 //按照格式的输出 206 Console.WriteLine("-------名称------价格---------是否辛辣-----------是否荤菜-------------"); 207 foreach (var list in lists[keys]) 208 { 209 Console.WriteLine(string.Format("------{0}----{1}------------------{2}-------------{3}-----------", list.CName, list.CPrice, list.IsHot ? "是" : "否", list.ISMeat ? "是" : "否")); 210 } 211 212 Console.WriteLine(string.Format("--------------人均消费:{0}------------", keys)); 213 Console.ReadKey(); 214 215 }
①输入菜的数目,计算各种素菜数目,荤菜数目,辣菜数目,清淡菜数目,把其各种菜品的菜添加到泛型数目中。
②输入荤菜,素菜,辣菜,清淡菜的数目,判断他是否满足相应的总菜的数目。
③将每种满足的菜式放入泛型数组中,计算相应的人均数目,放入键值对。
④ 计算相应键值对最接近12元的键, 将其对应的键的值输出,就满足题意。
最终,运行结果,效果如下:
这就是我的一点点的想法,还有很多不够。一、他中时间算法复杂度是o(n^4).二、还有一个错误,你找的到吗?