我们面临的基本问题是“邮资为m时可否用少于等于k张邮票来组成”,这是一个yes or no的特殊化问题,它所对应的一般化问题为“组成邮资为m时至少需要多少张邮票”,如果解决了一般化问题则特殊化问题就容易知道了。(想问题时,如果遇到了一个特殊化问题就同时去想想对应的一般化问题,同样,如果遇到一般化问题也同时想想对应的特殊化问题。)
下面简单对“组成邮资为m时至少需要多少张邮票”这个问题给出动规方程。
用values[]表示每种邮票的面值,用needs[i]表示组成邮资 i 至少需要邮票的张数,则有:
needs[i] = min{needs[ i - values[j] ] + 1}, 其中 1 <= j <= n ,且 i - values[j] > 0。
Code /**//* ID: sdjllyh1 PROG: stamps LANG: JAVA complete date: 2009/1/17 complexity: O(n * m) author: LiuYongHui From GuiZhou University Of China more articles: www.cnblogs.com/sdjls */ import java.io.*; import java.util.*; publicclass stamps { privatestaticint n, k; privatestaticint m; privatestaticint[] values;//每种邮票的面值 privatestaticchar[] needs =newchar[2000000];//例needs[14]=6时表示组合出面额14至少需要6张邮票 publicstaticvoid main(String[] args) throws IOException { init(); run(); output(); System.exit(0); } privatestaticvoid run() { //先假设组合出每种面值需要很多张邮票 Arrays.fill(needs, Character.MAX_VALUE); //设置那些可用面值仅需要一张邮票 for (int i =0; i < n; i++) { needs[values[i]] =1; } //从m=1开始直到找到一个面额需要的张数大于k m =1; while (needs[m] <= k) { m++; for (int i =0; i < n; i++) { if (values[i] < m) { needs[m] = min(needs[m], (char)(1+ needs[m - values[i]])); } } } } privatestaticchar min(char c1, char c2) { if (c1 < c2) { return c1; } else { return c2; } } privatestaticvoid init() throws IOException { BufferedReader f =new BufferedReader(new FileReader("stamps.in")); char[] buff =newchar[1000]; f.read(buff); StringTokenizer st =new StringTokenizer(String.valueOf(buff)); k = Integer.parseInt(st.nextToken()); n = Integer.parseInt(st.nextToken()); values =newint[n]; for (int i =0; i < n; i++) { values[i] = Integer.parseInt(st.nextToken()); } f.close(); } privatestaticvoid output() throws IOException { PrintWriter out =new PrintWriter(new BufferedWriter(new FileWriter("stamps.out"))); out.println(m -1); out.close(); } }
This article is from an interview with Zuhaib Siddique, a production engineer at HipChat, makers of group chat and IM for teams.
HipChat started in an unusual space, one you might not