例2 :
在这样一个arr数组中
1 2 3 4 5 6 7 找出互不相临的n个数,使这些数的和最大。
依旧是一个求最优解的动态规划问题,求解的关键是找出每一个状态选和不选的指标函数。
选:
OPT(i) = OPT(i-2) + arr[i];
不选:
OPT(i) = OPT(i-1);
递归出口:
OPT(1) = arr[1];
OPT(2) = max(arr[1],arr[2]);
这时已经可以写出递归求解方法:
#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,1,2,4,1,7,8,3};
int rec_opt(int n) //rec_opt即上文中OPT,rec代表递归recursion
{
if(n == 1)
return 1;
else if(n == 2)
return max(arr[1],arr[2]);
int x1,x2;//x1是选的状态,x2是不选的状态
x1 =rec_opt(n-2)+arr[n];
x2 =rec_opt(n-1);
return max(x1,x2);
}
int main()
{
cout << rec_opt(7) <<endl;
return 0;
}
画出树形图:
如OPT(3)和OPT(4),递归求解过程存在重叠子结构。
在动态规划算法中使用opt数组记录每一个状态
#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,1,2,4,1,7,8,3};
int opt[10];
int dp_opt(int n)//rec代表是递归recursion
{
opt[1] = arr[1];
opt[2] = max(arr[1],arr[2]);
for(int i=3;i<=n;i++)
{
int x1,x2;//x1是选的状态,x2是不选的状态
x1 =dp_opt(i-2)+arr[i];
x2 =dp_opt(i-1);
opt[i] = max(x1,x2);
}
return opt[n];
}
int main()
{
cout << dp_opt(7) <<endl;
return 0;
}
例题3 :
在这样一个arr数组中
3 34 4 12 5 2 输入一个整数s,如果存在数组中的n数之和等于s则输出true,否则输出false。
本题依旧是求最优解的问题,求解的关键是找出每一个状态选和不选的指标函数。
定义subset(i,s)函数 ,第一个参数表示数组中当前位置i之前的所有数可选,s表示还需要的和 (subset是子集的意思)。
当s输入为9时
如果选arr[5] (arr[5] = 2)
subset(arr[5],9) = arr[5]+subset(arr[4],7);
如果不选arr[5]
subset(arr[5],9) = subset(arr[4],9));
递归出口:
1.s已经等于0时
if(s == 0)
return true;
2.当i = 0,s不等于0时
if(i == 0 && arr[i] == s)
return true;
else
return false;
3.当arr[i]>s时,不考虑选的情况
if(arr[i]>s)
return(subset(arr[i-1],s));
递归算法:
#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,3,34,4,12,5,2};
bool rec_opt(int n,int s)
{
if (s == 0)
return true;
else if(n == 1 && s!= arr[1])
return false;
else if(n == 1 && s == arr[1])
return true;
else if(arr[n] > s)
return rec_opt(n-1, s);
else
{
bool x1,x2;
x1 = rec_opt(n-1,s-arr[n]);
x2 = rec_opt(n-1, s);
return (x1 || x2);
}
}
int main()
{
int s;
cin >> s;
if(rec_opt(6, s))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}
动态规划:
#include <iostream>
#include <algorithm>
using namespace std;
int arr[10] = {0,3,34,4,12,5,2};
bool opt[10][101];
bool dp_opt(int n,int s)
{
bool x1,x2;
for(int i=0;i<=6;i++)
opt[i][0] = true;
for(int i=0;i<=101;i++)
opt[1][i] = false;
opt[1][4] = true;
for(int i=1;i<=6;i++)
for(int j = 0;j <= s;j++)
if(arr[i] > j)
opt[i][j] = opt [i-1][j];
else
{
x1= opt[i-1][j-arr[i]];
x2 = opt[i-1][j];
opt[i][j] = (x1 || x2);
}
return opt[6][s];
}
int main()
{
int s;
cin >> s;
if(dp_opt(6, s))
cout << "true" << endl;
else
cout << "false" << endl;
return 0;
}