组合商品问题

问题描述:http://blog.csdn.net/weixin_33226456/article/details/79506439

测试 test1.txt

3,3
2,3,1
bom1,2,1,1
bom2,1,1,0
bom3,0,1,1

代码框架 bom-frame.js(帮你做掉输入输出)

 1 // read from stdin
 2 process.stdin.setEncoding('utf8')
 3 let input = ''
 4 process.stdin.on('readable', () => {
 5   const chunk = process.stdin.read()
 6   if (chunk !== null) {
 7     input += chunk
 8   }
 9 })
10 process.stdin.on('end', () => {
11   const param = parseParam(input)
12   const answer = solve(param.items, param.boms)
13   console.log('match result:\n' + formatAnswer(answer, param.names))
14 })
15 
16 // format answer
17 function formatAnswer(c_answer, c_names) {
18   return c_answer
19     .map((value, i)=>({idx:i,val:value}))
20     .filter(x=>x.val>0)
21     .map(x=>c_names[x.idx]+'*'+x.val)
22     .join(',')
23 }
24 
25 // parse input params
26 function parseParam(c_input) {
27   const param = {}
28   const lines = c_input.split('\n')
29   const counts = lines[0].split(',')
30   const nItem = Number(counts[0])
31   const nBom = Number(counts[1])
32   const boms = lines.slice(2, 2 + nBom).map(x=>x.split(','))
33   param.nItem = nItem
34   param.nBom = nBom
35   param.items = lines[1].split(',').map(x=>Number(x))
36   param.boms = boms.map(x=>x.slice(1).map(x=>Number(x)))
37   param.names = boms.map(x=>x[0])
38   return param
39 }
40 
41 // ======== IGNORE CODES ABOVE FOR I/O ========
42 const maxNItem = 10
43 const maxNBom = 9
44 // ======== FOCUS ON SOLUTION BELOW ========
45 /* c_items: number of each item in order
46  * c_boms: list of boms, each item is a list of
47  */
48 function solve(c_items, c_boms) {
49   return Array(c_boms.length).fill(0) // ### replace with your own code. 
50 }

 

完整解答 bom.js

  1 // read from stdin
  2 process.stdin.setEncoding('utf8')
  3 let input = ''
  4 process.stdin.on('readable', () => {
  5   const chunk = process.stdin.read()
  6   if (chunk !== null) {
  7     input += chunk
  8   }
  9 })
 10 process.stdin.on('end', () => {
 11   const param = parseParam(input)
 12   const answer = solve(param.items, param.boms)
 13   console.log('match result:\n' + formatAnswer(answer, param.names))
 14 })
 15 
 16 // format answer
 17 function formatAnswer(c_answer, c_names) {
 18   return c_answer
 19     .map((value, i)=>({idx:i,val:value}))
 20     .filter(x=>x.val>0)
 21     .map(x=>c_names[x.idx]+'*'+x.val)
 22     .join(',')
 23 }
 24 
 25 // parse input params
 26 function parseParam(c_input) {
 27   const param = {}
 28   const lines = c_input.split('\n')
 29   const counts = lines[0].split(',')
 30   const nItem = Number(counts[0])
 31   const nBom = Number(counts[1])
 32   const boms = lines.slice(2, 2 + nBom).map(x=>x.split(','))
 33   param.nItem = nItem
 34   param.nBom = nBom
 35   param.items = lines[1].split(',').map(x=>Number(x))
 36   param.boms = boms.map(x=>x.slice(1).map(x=>Number(x)))
 37   param.names = boms.map(x=>x[0])
 38   return param
 39 }
 40 
 41 // ======== IGNORE CODES ABOVE FOR I/O ========
 42 const maxNItem = 10
 43 const maxNBom = 9
 44 // ======== FOCUS ON SOLUTION BELOW ========
 45 /* c_items: number of each item in order
 46  * c_boms: list of boms, each item is a list of
 47  * 
 48  * 1. Solution can be represented by *vec*(vector of boms used).
 49  *    *vec* is an vector in space N^*nBom*.
 50  * 2. a viable *vec* gives a sulution in which sum of any item
 51  *    in all boms is not greater than that given by *items*.
 52  * 3. There must be at least one solution with minimal rest item types
 53  *    on the edge of viable region. (But without some of these bom types may
 54  *    get result with less bom types (better solution for this problem))
 55  *    Edge means adding any bom to the *vec* will result in a nonviable *vec*.
 56  *    i.e. we can find the best solution in the set: number of each bom is 
 57  *    either 0 or the max number with other bom number fixed.
 58  *    (prove by yourself)
 59  * 4. Traversal near the edge can find the answer.
 60  * 5. Use sparse matrix to save space if you use DP.(I am not using DP here,
 61  *    but this is a suggestion for your implementation)
 62  * 6. This is not the fastest algorithm for this problem since there are still
 63  *    some ways to cut more branches while traversing for best solution.
 64  */
 65 function solve(c_items, c_boms) {
 66   // init to origin
 67   const vec = Array(c_boms.length).fill(0)
 68   const rest = c_items.slice()
 69   // lets first build a inverted index for finding related boms later
 70   const rel = c_boms.reduce((sum, cur, idx)=>cur.reduce((s,c,i)=>{
 71     if (c > 0) {
 72       if (s[i] != undefined) {
 73         s[i].push(idx)
 74       } else {
 75         s[i] = [idx]
 76       }
 77     }
 78     return s
 79   },sum),{})
 80   // recursive part
 81   const best = solveR(vec, 0, null, rest, c_boms, rel)
 82   return best.vec
 83 }
 84 
 85 /* recursive part:
 86  * With first *fixed* bom numbers fixed, find best vec
 87  */
 88 function solveR(c_vec, c_fixed, c_best, c_rest, c_boms, c_rel) {
 89   // case 0: end of recursion
 90   let vec = c_vec.slice()
 91   if (c_fixed == c_boms.length) {
 92     let rest = c_rest.slice()
 93     removeHelplessBom(vec, rest, c_boms)
 94     const scr = score(vec, rest)
 95     if (c_best == null || scr < c_best.score) {
 96       return {score: scr, vec: vec}
 97     } else {
 98       return c_best
 99     }
100   }
101   // case 1: not all bom numbers fixed
102   let distToEdge = c_boms[c_fixed].reduce((s, x, i) => {
103     if (x == 0) {
104       return s
105     }
106     let distI = Math.floor(c_rest[i] / x)
107     return s == null ? distI : s <= distI ? s : distI
108   }, null)
109   vec[c_fixed] += distToEdge;
110   let rest = calRest(c_rest, c_fixed, distToEdge, c_boms)
111   let best = solveR(vec, c_fixed + 1, c_best, rest,  c_boms, c_rel)
112   // check if we need to test cases with less *c_fixed*th bom
113   let tryReduce = c_boms[c_fixed].some(
114     (x, i) => x > 0 && c_rel[i].filter(x => x > c_fixed).length > 0
115   )
116   while(vec[c_fixed] > 0) {
117     vec[c_fixed] --
118     rest = calRest(rest, c_fixed, -1, c_boms)
119     best = solveR(vec, c_fixed + 1, best, rest, c_boms, c_rel)
120   }
121   return best
122 }
123 
124 // update rest value when *i*th com increase n
125 function calRest(c_rest, c_i, c_n, c_boms) {
126   const newRest = c_rest.slice()
127   return c_boms[c_i].reduce((sum,cur,idx)=>{sum[idx]-=cur*c_n;return sum}, newRest)
128 }
129 
130 /* Let's call the boms which none of their related item types
131  * is completely covered by boms "helpless" (helpless for better score).
132  */
133 function removeHelplessBom(vec, v_rest, c_boms) {
134   let rest = v_rest.slice();
135   vec.forEach((veci, i) => {
136     if (veci > 0) {
137       let helpful = c_boms[i].some((val, idx) => val > 0 && rest[idx] == 0)
138       if (!helpful) {
139         vec[i] = 0
140         rest = calRest(rest, i, -1 * veci, c_boms)
141       }
142     }
143   })
144   v_rest.length = 0
145   v_rest.push(...rest)
146 }
147 
148 // score a solution, the lower the better
149 function score(c_vec, c_rest) {
150   const nUsedBomType = c_vec.filter(x=>x>0).length
151   const nRestType = c_rest.filter(x=>x>0).length
152   return nRestType * (maxNBom + 1) + nUsedBomType
153 }

 

posted @ 2018-03-21 02:53  rainforwind  阅读(191)  评论(0编辑  收藏  举报