【回溯】B056_LG_郵票面值設計(暴搜 + dp)

一、Problem在這裏插入圖片描述

3 2

1 3
MAX=7

二、Solution

方法一:暴搜 + dp

  • 定義狀態
    • dp[i]dp[i] 表示組成郵資值 i 所需要的最小郵票數
  • 思考狀態轉移方程
    • 如果 dp[vala[i]]+1<dp[val]dp[val-a[i]] + 1 < dp[val],則有 dp[val]=dp[vala[i]]+1dp[val] = dp[val-a[i]] + 1,表示如果 vala[i]val - a[i]a[i]a[i] 組成的郵資值所需的郵票數比其它郵票組成所需的郵票數要少的話,更新即可
  • 思考初始化:
    • dp[1]=1dp[1] = 1,表示組成郵資值 1 使用 1 張 1 面值的郵票是最少方案

下面就是定義 dfs 邏輯了:

  • dfs 的搜索範圍每次都以上一個郵資值 a[k-1] 爲開始,每次遞增 1,直到當前找到的最大郵資值。
  • 剪枝 1:讓郵票的面值從 a[k-1] + 1 開始保持遞增,避免重複,當然特可以用 boolean[] vis 記錄某種面值的使用狀態。
  • 剪枝 2:
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static class Solution {
		int n, m, max, maxn = 2000, a[], res[], dp[], INF = 0x3f3f3f3f;
		int get(int k) {
			int val = 1;
			for (int i = 1; i < maxn; i++)  dp[i] = INF;
			for (int i = 1; i <= k; i++)    dp[a[i]] = 1;
	        while (dp[val] <= n) {
				val++;
				for (int i = 1; i <= k; i++) {
					if (val > a[i] && dp[val-a[i]]+1 < dp[val])
						dp[val] = dp[val-a[i]]+1;
				}
		    }
			return val;
		}
		void dfs(int k) {
		    int t = get(k-1);
			if (k > m) {
			    if (t-1 > max) {
			        max = t-1;
				    for(int i = 1; i <= m; i++) 
				        res[i] = a[i];
			    }
			    return;
			}
			for (int i = a[k-1]+1; i <= t; i++) {
				a[k] = i;
				dfs(k+1);
			}
		}
		void init() {
			Scanner sc = new Scanner(new BufferedInputStream(System.in));
			n = sc.nextInt(); m = sc.nextInt();
			res = new int[maxn];
			a = new int[maxn];
			dp = new int[maxn];
			a[1] = 1;
			dfs(2);
			for (int i = 1; i <= m; i++) System.out.printf("%d ", res[i]); System.out.println();
			System.out.printf("MAX=%d", max);
		}
	}
    public static void main(String[] args) throws IOException {  
        Solution s = new Solution();
		s.init();
    }
}

複雜度分析

  • 時間複雜度:O(...)O(...)
  • 空間複雜度:O(...)O(...)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章