l3-001 湊零錢 (30 分)
輸入第一行給出兩個正整數:n(≤104)是硬幣的總個數,m(≤102)是韓梅梅要付的款額。第二行給出 n 枚硬幣的正整數面值。數字間以空格分隔。
在一行中輸出硬幣的面值 v1≤v2≤⋯≤vk,滿足條件 v1+v2+...+vk=m。數字間以 1 個空格分隔,行首尾不得有多餘空格。若解不唯一,則輸出最小序列。若無解,則輸出no solution
。
注:我們說序列比「小」,是指存在 k≥1 使得 a[i]=b[i] 對所有 i解題思路
由於要輸出最小序列,所以先給陣列v排序。
本題的01揹包中,dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + v[i])。也就是說dp[i][j]的值是由dp[i-1][j]和dp[i-1][j-v[i]] + v[i]中的較大者決定的,當兩者相同時,就會產生多解。反過來說,dp[i][j]可能會決定dp[i+1][j]或者dp[i+1][j+v[i+1]]。用乙個二維陣列way[i][j](初始化為0)來儲存dp[i][j]所決定的物件(1為dp[i+1][j],2為dp[i+1][j+v[i+1]],3為兩者都能決定)。然後就把路徑記錄好了,可以用來搜尋了。
如果dp[n][m]小於m說明沒有方案可以湊到,就直接輸出"no solution"。
否則,因為要求輸出最小序列,所以要從小到大試過去。開乙個迴圈i從0到n-1,每次從(i, 0)開始dfs,因為dp[i+1][v[i+1]]都是由dp[i][0]決定的(就是第乙個放入揹包的要從小到大嘗試)。然後用乙個stack儲存答案,如果找到了等於m的點,就返回true,當dp[i][j]可以決定dp[i+1][j+v[i+1]]的時候(選擇v[i+1]加入揹包),在返回true前把v[i+1]入棧。如果沒有路了(way[i][j] == 0),就返回false。(這段說的有點亂,看**吧)
還有一點需要注意,當way[i][j]==3的時候,要先dfs (i+1,j+v[i+1])再dfs(i+1,j)。因為前者把v[i+1]放入揹包,後者沒有,那就會放入乙個比v[i+1]大的。
dfs**如下
bool dfs(int x, int y, stack& sta)
} else if(way[x][y] == 2)
} else if(way[x][y] == 3)
if(dfs(x + 1, y, sta))
return true;
} return false;
}
完整**如下
#include #include #include #include #include using namespace std;
int dp[10005][105];
int v[10005];
int way[10005][105]; //1,x+1,y 2,x+1,y+v[x+1] 3,1and2
int n, m;
bool dfs(int x, int y, stack& sta)
} else if(way[x][y] == 2)
} else if(way[x][y] == 3)
if(dfs(x + 1, y, sta))
return true;
} return false;
}int main()
else //已經決定了一種
way[i - 1][j] = 3;
}
else
if(dp[i - 1][j] <= dp[i - 1][j - v[i] + v[i]])
}
}}
if(dp[n][m] != m)
cout << "no solution" << endl;
else
cout << endl;
break;
}}
} }return 0;
}
L3 001 湊零錢 (01揹包)
時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...
L3 001 湊零錢 dp 滿01揹包
時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...
L3 001 湊零錢(dfs或者01揹包)
時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...