挑战程序竞赛系列(55):4.4 双端队列(2)
来源:互联网 发布:古由卡怎么样 知乎 编辑:程序博客网 时间:2024/06/03 20:34
挑战程序竞赛系列(55):4.4 双端队列(2)
详细代码可以fork下Github上leetcode项目,不定期更新。
练习题如下:
- POJ 3260: The Fewest Coins
POJ 3260: The Fewest Coins
还以为直接 DP求解,但没想到可以双DP求解+枚举,这思路没谁了,第一次接触,我就一个服字。
大致思路,因为农民伯伯不确定到底是那种方案下获得的硬币个数最小,所以他就尝试着把(T+i)的钱给商家,这样一来,商家找零i元,OK,那么现在问题就转化成了:
付钱: dp_pay[i]: i表示付给商家的最小硬币个数(多重背包)
找钱: dp_change[j]:j表示店家找零的最小硬币个数(完全背包)
嗯哼,T+i中,i的上界该如何确定呢,如果没有相关组合知识,还真难做。
证明可以参考:(并不理解)
http://www.hankcs.com/program/algorithm/poj-3260-the-fewest-coins.html
不过该博文中贴出的组合数学的一个知识点,该证明还是容易理解的,也很巧妙。
这里再补充下P341多重背包转01背包的理解,首先
其中
接着 别忘了价格和重量都需要乘上系数即可。
代码如下:
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.util.Arrays;import java.util.StringTokenizer;public class Main{ String INPUT = "./data/judge/201709/P3260.txt"; public static void main(String[] args) throws IOException { new Main().run(); } static final int MAX_T = 10000 + 4; static final int MAX_N = 100 + 2; static final int MAX_V = 120 + 1; static final int INF = 1 << 29; int N, T; int[] V = new int[MAX_N]; int[] C = new int[MAX_N]; int max_v; int[] dp_change = new int[MAX_T + MAX_V * MAX_V]; int[] dp_pay = new int[MAX_T + MAX_V * MAX_V]; //完全背包 void dp_complete_pack(int n, int W) { Arrays.fill(dp_change, INF); dp_change[0] = 0; for (int i = 0; i < n; ++i) { for (int j = V[i]; j <= W; ++j) { dp_change[j] = Math.min(dp_change[j], dp_change[j - V[i]] + 1); } } } //多重背包转二进制 void dp_multiple_pack(int n, int W) { Arrays.fill(dp_pay, INF); dp_pay[0] = 0; for (int i = 0; i < n; ++i) { int num = C[i]; for (int k = 1; num > 0; k <<= 1) { int mul = Math.min(k, num); for (int j = W; j >= mul * V[i]; --j) { dp_pay[j] = Math.min(dp_pay[j], dp_pay[j - mul * V[i]] + mul); } num -= mul; } } } void solve() { N = ni(); T = ni(); for (int i = 0; i < N; ++i) { V[i] = ni(); max_v = Math.max(max_v, V[i]); } int sum = 0; for (int i = 0; i < N; ++i) { C[i] = ni(); sum += V[i] * C[i]; } int min = INF; max_v = Math.min(max_v * max_v, sum - T); dp_multiple_pack(N, T + max_v); dp_complete_pack(N, T + max_v); for (int i = max_v; i >= 0; --i) { min = Math.min(min, dp_change[i] + dp_pay[i + T]); } if (min == INF) { out.println("-1"); } else { out.println(min); } } FastScanner in; PrintWriter out; void run() throws IOException { boolean oj; try { oj = ! System.getProperty("user.dir").equals("F:\\java_workspace\\leetcode"); } catch (Exception e) { oj = System.getProperty("ONLINE_JUDGE") != null; } InputStream is = oj ? System.in : new FileInputStream(new File(INPUT)); in = new FastScanner(is); out = new PrintWriter(System.out); long s = System.currentTimeMillis(); solve(); out.flush(); if (!oj){ System.out.println("[" + (System.currentTimeMillis() - s) + "ms]"); } } public boolean more(){ return in.hasNext(); } public int ni(){ return in.nextInt(); } public long nl(){ return in.nextLong(); } public double nd(){ return in.nextDouble(); } public String ns(){ return in.nextString(); } public char nc(){ return in.nextChar(); } class FastScanner { BufferedReader br; StringTokenizer st; boolean hasNext; public FastScanner(InputStream is) throws IOException { br = new BufferedReader(new InputStreamReader(is)); hasNext = true; } public String nextToken() { while (st == null || !st.hasMoreTokens()) { try { st = new StringTokenizer(br.readLine()); } catch (Exception e) { hasNext = false; return "##"; } } return st.nextToken(); } String next = null; public boolean hasNext(){ next = nextToken(); return hasNext; } public int nextInt() { if (next == null){ hasNext(); } String more = next; next = null; return Integer.parseInt(more); } public long nextLong() { if (next == null){ hasNext(); } String more = next; next = null; return Long.parseLong(more); } public double nextDouble() { if (next == null){ hasNext(); } String more = next; next = null; return Double.parseDouble(more); } public String nextString(){ if (next == null){ hasNext(); } String more = next; next = null; return more; } public char nextChar(){ if (next == null){ hasNext(); } String more = next; next = null; return more.charAt(0); } } static class ArrayUtils { public static void fill(int[][] f, int value) { for (int i = 0; i < f.length; ++i) { Arrays.fill(f[i], value); } } public static void fill(int[][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } public static void fill(int[][][][] f, int value) { for (int i = 0; i < f.length; ++i) { fill(f[i], value); } } }}
做了一个小小的优化,计算了农民伯伯能够达到的最大支付金额。
阅读全文
0 0
- 挑战程序竞赛系列(55):4.4 双端队列(2)
- 挑战程序竞赛系列(54):4.4 双端队列(1)
- 挑战程序竞赛系列(56):4.4 双端队列(3)
- 挑战程序竞赛系列(9):2.4优先队列
- 挑战程序竞赛系列(53):4.4 栈
- 挑战程序竞赛系列(82):4.3 LCA(2)
- 挑战程序竞赛系列(81):4.3 LCA(1)
- 挑战程序竞赛系列(1):2.3动态规划
- 挑战程序竞赛系列(4):2.1深度优先搜索
- 挑战程序竞赛系列(5):2.1广度优先搜索
- 挑战程序竞赛系列(6):2.1穷尽搜索
- 挑战程序竞赛系列(10):2.4并查集
- 挑战程序竞赛系列(11):2.5最短路径
- 挑战程序竞赛系列(12):2.5最小生成树
- 挑战程序竞赛系列(13):2.6辗转相除法
- 挑战程序竞赛系列(14):2.6素数
- 挑战程序竞赛系列(15):2.6快速幂运算
- 挑战程序竞赛系列(16):3.1最大化最小值
- Spring Cloud 的 Eureka HA
- Kotlin------类和对象(二)
- [转]opencv实现几幅图像拼接成一整幅大图
- 基于WebRTC的Android数字楼宇对讲系统回声消除
- 百度 UNIT 技术负责人揭秘:如何让你的对话系统更智能
- 挑战程序竞赛系列(55):4.4 双端队列(2)
- ubuntu解压RAR文件
- c++中->和.的区别
- [初学笔记] matlab 中的 function, return,global
- Java面试笔试题大汇总
- 基于SM32的脉冲输出定位控制(精确脉冲个数控制,PWM)
- Makefile 中:= ?= += =的区别
- JavaScript的垃圾回收机制与内存管理
- 算法和数据结构