1. 程式人生 > >DP DAG 9-3硬幣問題(演算法競賽入門經典p162)

DP DAG 9-3硬幣問題(演算法競賽入門經典p162)

有n種硬幣,面值分別為V1,V2,V3,.....Vn,每種都有無限多。給定非負整數S,可以選用多少個硬幣,使得面值之和恰好為S?輸出硬幣數目的最小值和最大值。1<=n>=100,

0<=S<=10000,1<=Vi<=S.

思路:本題是固定終點和起點的DAG動態規劃。我們把每種面值看做一個點,表示“還需要湊足的面值”,則初始狀態為S,目標狀態為0。如當前在狀態i,沒使用一個硬幣j,狀態變轉移到i-Vj。

我對於這道題目的意義就是想討論一下書上所說的三種DP方式和路徑輸出方式,因為書上沒有給出完整的程式碼,我覺得整理一下,對DAG上DP的學習非常有幫助。

第一:遞推法。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=10000;
const int inf=1000000000;
int n,S;
int Min[maxn],Max[maxn],V[maxn];

void print_ans(int *dp,int S)
{
	for(int i=1;i<=n;i++)
	{
		if(S>=V[i]&&dp[S]==dp[S-V[i]+1])
		{
			printf("%d\n", i);
			print_ans(dp,S-V[i]);
			break;
		}
	}
}
int main()
{
	int i,j;
    while(scanf("%d%d",&n,&S)==2)
    {	
    	memset(Min,0,sizeof(Min));
    	memset(Max,0,sizeof(Max));
    	memset(V,0,sizeof(V));
    	for(i=1;i<=n;i++)     scanf("%d",&V[i]);
    	for(i=1;i<=n;i++)	  Min[i]=inf,Max[i]=-inf;

    	Min[0]=Max[0]=0;
    	for(i=1;i<=S;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			if(i>=V[j])
    			{
    				Min[i]=min(Min[i],Min[i-V[j]]+1);
    				Max[i]=max(Max[i],Max[i-V[j]]+1);
    			}
    		}
    	}
    }
    return 0;
}
第二種:遞推法,但是路勁已經優化,用一個min_coin[],max_coin[]來表示“面值還差i時”的面值種類j.雖然我現在還在痛苦的學習DP中,也談不上什麼經驗,但是我非常喜歡這種方法。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=10000;
const int inf=1000000000;

int Min[maxn],Max[maxn],min_coin[maxn],max_coin[maxn];
int V[maxn];
int n,S;
void print(int *dp_path,int S)
{
	while(S)
	{
		printf("%d",dp_path[S]);
		S-=V[dp_path[S]];
	}
}

int main()
{
	int i,j;
        scanf("%d%d",&n,&S);
        for(i=1;i<=n;i++)		scanf("%d",&V[i]);
	Min[0]=Max[0]=0;
	for(i=1;i<=n;i++)		Min[i]=inf,Max[i]=-inf;
	for(i=1;i<=S;i++)
	{
		for(j=1;j<=n;j++)
		{
		        if(i>=V[j])
			{
				if(Min[i]>Min[i-V[j]]+1)
				{
					Min[i]=Min[i-V[j]+1];
					min_coin[i]=j;
				}
				if(Max[i]<Max[i-V[j]]+1)
				{
					Max[i]=Max[i-V[j]]+1;
					max_coin[i]=j;
				}
			}
		}
	}
	print(min_coin,S);
	printf("\n");
	print(max_coin,S);
	printf("\n");
	return 0;
}
第三種:記憶搜尋,要搜尋兩次。。。待續,回到寢室在寫 


相關推薦

DP DAG 9-3硬幣問題演算法競賽入門經典p162)

有n種硬幣,面值分別為V1,V2,V3,.....Vn,每種都有無限多。給定非負整數S,可以選用多少個硬幣,使得面值之和恰好為S?輸出硬幣數目的最小值和最大值。1<=n>=100, 0<=S<=10000,1<=Vi<=S. 思路:本題是

使用檔案進行輸入輸出的兩種方式演算法競賽入門經典第2章)

使用檔案進行輸入輸出的兩種方式: 1,  重定向       freopen("input.txt", "r", stdin);       freopen("output.txt", "w", stdout);       上述語句將使得scanf從檔案input.

ACM準備之路演算法競賽入門經典1)排列

問題:1~9,組成三個三位數,abc、def,ghi,每個數字用且只用一次,使三個數為1:2:3,每行一個解。這是書上2-6,由於當時想的方法太麻煩,然後去網上找了大佬的一篇文章,具體是哪位的不太記得了,在此說聲謝謝,確實想的比我的簡單多了。 ps:良品鋪子的芒果乾不錯

演算法競賽入門經典第二版)第三章陣列和字串習題3-4週期串

如果一個字串可以由某個長度為k的字串重複多次得到,則稱該串以k為週期。例如abcabcabc以3為週期(注意,它也以6和12為週期)。輸入一個長度不超過80的字串,輸出其最小週期 #include<stdio.h> int main() { char a[100];

演算法競賽入門經典第二版)第三章陣列和字串習題3-3數數字

把前n(n<=10000)個整數順次解除安裝一起:123456789101112…數一數0~9各出現多少次(輸出10個整數,分別是0,1,…,9出現的次數) #include<stdio.h> #define N 100000 char s[N],temp[10]; i

演算法競賽入門經典第二版)第三章陣列和字串習題3-2分子量

給出一種物質的分子式不帶括號,求分子量。本題中的分子式只包含4種原子分別為CHON,原子量分別為12.01,1.008,16.00,14.01(單位g/mol)。例如,C6H5OH的分子量是94.108g/mol #include <stdio.h> int main() {

演算法競賽入門經典第二版)第三章陣列和字串習題3-1得分

給出一個由O和X組成的串(長度1-80)統計得分。每個O的得分為目前連續出現的O的個數,X的得分為0。 #include <stdio.h> int main() { int b=0,c=0; int j=1; char a[80]; scan

演算法競賽入門經典第二版)第三章陣列和字串中競賽題目例題3-5 生成元

如果x加上x的各個數字之和得到y,就說x是y的生成元。給出n(1<=n<=100000)求最小生成元。無解輸出0.例如n=216時的解為198 分析 本題看起來是個數學題實則不然。假設所求生成元為m不難發現m<n.換句話說只需列舉所有的m<n看看有沒有哪個數是n的

演算法競賽入門經典第二版)第三章陣列和字串中競賽題目例題3-4猜數字

實現一個經典猜數字遊戲。給定答案序列和使用者猜的序列,統計有多少數字位置正確A,有多少數字在兩個序列都出現過但位置不對B 輸入包含多組資料。每組第一行為序列長度為n,第二行是答案序列,接下來是若干猜測序列。猜測序列全0時該組資料結束。n=0時輸入結束 [分析] 直接統計可得A,為

演算法競賽入門經典第二版)第三章陣列和字串中競賽題目選講例題3-3迴文詞

輸入一個字串,判斷它是否為迴文串以及映象串。輸入字串保證不含數字0。所謂迴文串,就是反轉以後和原串相同,如abba和madam。所有映象串,就是左右映象之後和原串相同,如2S和3AIAE。注意,並不是每個字元在映象之後都能得到一個合法字元。在本題中,每個字元的映象如圖3-3所示(空白

演算法競賽入門經典第二版)第三章陣列和字串中競賽題目選講例題3-2WERTYU

把手放在鍵盤上時,稍不注意就會往右錯一位。這樣,輸入Q會變成輸入W,輸入J會變成輸入K等。 輸入一個錯位後敲出的字串(所有字母均為大寫),輸出打字員本來想打出的句子。輸入保證合法,即一定是錯位之後的字串。例如輸入中不會出現大寫字母A。 #include<stdio.h> ch

演算法競賽入門經典》 習題3-9 子序列

《演算法競賽入門經典》 習題3-9 子序列 輸入兩個字串s和t,判斷是否可以從t中刪除0個或多個字元(其他字元順序不變),得到字串s。例如,abcde可以得到bce,但無法得到dc。 #include<stdio.h> #include<string.h> i

演算法競賽入門經典(第二版) 習題3-5 謎題Puzzle) UVa227 Finals1993

Page 57 Description 一個5*5的網格中恰好有一個格子是空的,其他格子各有一個字母,四條指令A,B,L,R分別表示將空格上、下、左、右移動。輸入初始網格(以Z結束)和一串指令(以0結束),輸出執行操作後的網格。越界則輸出“This puzzle has n

演算法競賽入門經典第2版)習題4-3 黑白棋 Othello UVa220

這題邏輯和習題4-1象棋很相似,沒什麼特別的。 第一次提交報wa,添加了若干樣例測試,發現邏輯無誤。 與樣例輸出對拍後發現輸出尾部多了一個換行符,修改後ac。 //#define LOCAL //#define TESTING #include<stdio.h>

演算法競賽入門經典第2版)習題3-4 週期串 Periodic Strings UVa445

這題把我虐哭了。 提交了13次才ac。 演算法本身沒什麼好說的,UVa上html版和pdf版的輸入輸出格式要求不一樣,以html版為準。 而且html版的輸入輸出格式都有點奇葩,不認真看原文細節是ac不了的。 參考了他的例程,我才找到問題的解決辦法。 UVa評測系統中的空

演算法競賽入門經典(第二版) 習題3-11 換低檔裝置Kickdown) UVa1588 NEERC2006

Page 59 題意:給出兩個長度分別為n1,n2且每列高度只為1或者2的長條,需要將它們放入一個高度為3的容器,問容器的最短長度。 思路:兩個字串起始端對齊,分兩個方向移動,得到兩個最短長度,再取較

演算法競賽入門經典 習題2-3 韓信點兵hanxin)

習題2-3 韓信點兵(hanxin) 相傳韓信才智過人,從不直接清點自己軍隊的人數,只要讓士兵先後以三人一排、五人一排、七人一排地變換隊形,而他每次只掠一樣隊伍的排尾就知道總人數了。輸入3個非負整數a,b,c,表示每種隊形排尾的人數(a<3,b<5

演算法競賽入門經典第2版)習題3-5 謎題Puzzle) Uva227

C++編寫 #include<iostream> using namespace std; int main() { int x = 2, y = 1; char Pu

UVa220 演算法競賽入門經典第2版)習題4-3 黑白棋 Othello

 老規則   題目解釋看他們的  程式碼看我的。。         可能我的程式碼略微濃縮一些。  。。 。。我找了半天,,程式碼寫的都好長。,要是看懂了題目的話 就看我的程式碼吧。 http://blog.csdn.net/kyoma/article/details/51

演算法競賽入門經典:習題3-8 手機鍵盤keyboard)

輸入一個由小寫字母組成的英文單詞,輸出用手機的預設英文輸入法的敲鍵序列。例如要打出pig這個單詞,需要按1次p,3次i,(稍作停頓後)1次g,記為p1i3g1。 #include<stdio.h> #include<string.h> #define