算法競賽入門經典 例題9-3 硬幣問題

/*算法競賽入門經典  例題9-3 硬幣問題  
 * d[i]表示從i出發到結點0的最長路徑長度  d[0]=0  
 * 固定起點s 固定終點0  
 * 狀態轉移方程: d[i] = max{d[j] + 1} 
 * */
 
import java.util.Arrays;
import java.util.Scanner;

public class Coins {
	static final int MAX = 1<<30;
	static final int MIN = -MAX;
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		Coins c = new Coins();
		int n = scanner.nextInt();
		int[] v = new int[n+1];//0不使用
		for(int i=1; i<=n; i++) {
			v[i] = scanner.nextInt();
		}
		int s = scanner.nextInt();
		int[] d = new int[s+1];
		Arrays.fill(d, -1);
		d[0] = 0;// d[0]必須初始化爲0
		
		/*
		boolean[] isFound = new boolean[]{false};
		c.dp(s,d,v,isFound);
		if(!isFound[0]) {
			System.out.println("no answer!");
		}else {
			c.print(d, s, v);
		}
		*/
		
		//遞推法
		int[] min = new int[s+1];
		int[] max = new int[s+1];
		Arrays.fill(min, MAX);
		Arrays.fill(max, MIN);  
		min[0] = max[0] = 0;
		
		for(int i=1; i<=s; i++) {
			for(int j=1; j<=n; j++) {
				if(i >= v[j]) {
					min[i] = min[i] < min[i-v[j]] + 1 ? min[i] : min[i-v[j]] + 1;
					max[i] = max[i] > max[i-v[j]] + 1 ? max[i] : max[i-v[j]] + 1;
				}
			}
		}
		c.print(min, s, v);
		System.out.println();
		c.print(max, s, v);
	}
	
	//記憶化搜索  
	int dp(int s, int[] d, int[] v, boolean[] isFound) {
		if(s == 0) isFound[0] = true;
		if(d[s] != -1) return d[s];
		d[s] = MIN;
		for(int i=1; i<v.length; i++) {
			if(s >= v[i]) {
				int temp = dp(s-v[i],d,v,isFound) + 1;
				d[s] = d[s] > temp ? d[s] : temp;
			}
		}
		return d[s];
	}
	
	void print(int[] d, int s, int[] v) {
		int i;
		for(i=1; i<v.length; i++) {
			if(s>=v[i] && d[s] == d[s-v[i]] + 1) {
				System.out.printf("%d ",i);
				print(d,s-v[i],v);
				break;
			}
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章