百度之星,是全球最大的中文搜索引擎,百度公司面向中國高校學生和編程愛好者所舉辦的高水平的程序設計大賽。他所考試的題目,全部都是算法的題目。
鄙人雖然是一個.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<N<=16,0<=N,0<M<=N,0<=12),分別表示菜單上菜的數目,飯團 25 需要點的菜的數目,就餐的人數。<K<=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<N<=16,0<=N,0<M<=N,0<=12),分別表示菜單上菜的數目,飯團 69 需要點的菜的數目,就餐的人數。<K<=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,0<N<=16,0<=N,0<M<=N,0<=12),分別表示菜單上菜的數目,飯團需要點的菜的數目,就餐的人數。<K<=12),分別表示菜單上菜的數目,飯團需要點的菜的數目,就餐的人數。 4 緊接着 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<Cai> caisMeat = new List<Cai>(); 19 List<Cai> caisNMeat=new List<Cai>(); 20 List<Cai> caisHot=new List<Cai>(); 21 List<Cai> caisNHot=new List<Cai>(); 22 //記錄比較的數組 23 Dictionary<double,List<Cai>> lists = new Dictionary<double, List<Cai>>(); 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<Cai> temps = new List<Cai>(); 161 List<Cai> temp1=new List<Cai>(); 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<Cai>(); 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).二、還有一個錯誤,你找的到嗎?