最少找零數
給定面值爲v[0], v[1]…v[n-1]元的硬幣若干,如何用最少的硬幣湊夠total元?
狀態:dp[i]表示湊夠 i 元需要的最少硬幣數
狀態轉移方程:dp[i] = min { dp[ i-v[j] ]+1},其中i >= v[j],j=0..n-1。
const int maxn = 100, INF = 1 << 27;
void dp_coin() //動態規劃求最少找零數量
{
int n, v[100], dp[1000]; //v[i]表示幣值,dp[i]表示湊夠i元需要的最少硬幣數
cin >> n;
for (int i = 0; i<n; ++i)
cin >> v[i];
int total;
cin >> total;
//狀態轉移方程:dp[i] = min{dp[i-v[j]]+1 | i >= v[j]}
fill(dp, dp+1000, INF); //初始化爲INF
dp[0] = 0; //初始狀態
for(int i = 1; i <= total; ++i)
{
for (int j = 0; j < n; ++j) //遍歷幣值
{
if (i >= v[j] && dp[i-v[j]] + 1 < dp[i])
dp[i] = dp[i-v[j]] + 1;
}
cout << i << " yuan need " << dp[i] << " coins" << endl;
}
}
最長遞增子序列(LIS)
給出N個數a[0], a[1]…a[n-1],求出最長遞增(或非降)子序列的長度。
狀態:dp[i]表示前i個數中,以a[i]結尾的最長公共子序列的長度。
狀態轉移方程:dp[i] = max{1, dp[j]+1}, 其中j < i且a[j] < a[i]。
void dp_LIS() //動態規劃求最長遞增子序列長度
{
int n, a[100], dp[100];
cin >> n;
for (int i = 0; i<n; ++i)
cin >> a[i];
//狀態轉移方程:dp[i] = max{1, dp[j]+1}, 其中j<i且a[j]<a[i]
int maxlen = 1; //LIS長度
for (int i = 0; i < n; ++i)
{
dp[i] = 1; //默認爲1
for (int j = i; j>=0; --j) //向前遍歷,找到比自己小的數a[j]
{
if (a[j] < a[i] && dp[j]+1 > dp[i]) //加在a[j]後的子序列更長
dp[i] = dp[j]+1;
}
if (dp[i] > maxlen) maxlen = dp[i];
}
cout << maxlen << endl;
}
最長公共子序列(LCS)
狀態:dp[i][j]表示a[0..i-1]和b[0..j-1]的LCS的長度
狀態轉移方程:
char dir[101][101]; //記錄方向用於打印
char ans[100]; //存放LCS的結果
int cnt = 0;
void print_LCS(int i, int j, const string &a)
{
if (i == 0 || j == 0)
{
for (int i = cnt-1; i>=0; --i) //輸出LCS
cout << ans[i];
cout << endl;
return;
}
if (dir[i][j] == 'q') //出現相同字符,向左上角回溯
{
ans[cnt++] = a[i-1];
print_LCS(i-1, j-1, a);
}
else if (dir[i][j] == 'w') //向上邊回溯
print_LCS(i-1, j, a);
else if (dir[i][j] = 'a') //向左邊回溯
print_LCS(i, j-1, a);
}
void dp_LCS() //動態規劃求最長公共子序列長度
{
string a,b;
cin >> a >> b;
int dp[101][101];
fill(dp[0], dp[0]+101*101, 0);
//a豎着放作爲行,b橫着放作爲列,注意空出第0行和第0列
for (int i = 1; i <= a.length(); ++i)
{
for (int j = 1; j <= b.length(); ++j)
{
if (a[i-1] == b[j-1]) //-1是因爲字符串下標從0開始,而這裏填dp矩陣從(1,1)開始
{
dp[i][j] = dp[i-1][j-1] + 1;
dir[i][j] = 'q'; //左上角
}
else if (dp[i-1][j] >= dp[i][j-1])
{
dp[i][j] = dp[i-1][j];
dir[i][j] = 'w'; //上一格
}
else if (dp[i-1][j] < dp[i][j-1])
{
dp[i][j] = dp[i][j-1];
dir[i][j] = 'a'; //左一格
}
cout << dp[i][j] << ' ';
}
cout << endl;
}
cout << "Longest Common Subsequence: " << endl;
cout << "Length: " << dp[a.length()][b.length()] << endl;
cout << "Results: ";
print_LCS(a.length(), b.length(), a);
}