#include<iostream>
#include<Windows.h>
#include<assert.h>
#include <algorithm>
#include <functional>
#include<vector>
#include<math.h>
#include<unordered_map>
using namespace std;
//买书问题
#if 0
int main(void)
{
double discount[6] = { 0, 1, 1.9, 2.7, 3.2, 3.75 };//存放购买不同本数的折扣
int book[6] = { 0 };
int bookCount = 0;//书本总类目
int bookPrice = 8;//书本价格
cout << "请输入五类书中每一类书的数目:" << endl;
for (int i = 1; i <= 5; i++)
{
cin >> book[i];//输入各类书本的数目
}
sort(book + 1, book + sizeof(book) / sizeof(int), greater<int>());//保证Y1>=Y2>=Y3>=Y4>=Y5
float arr[6][6][6][6][6] = { 0 };//存放折扣计算过程
float minDis[6][6][6][6][6] = { 0 };//存放享有的最大折扣
int y1 = 0;
int y2 = 0;
int y3 = 0;
int y4 = 0;
int y5 = 0;
/*
实现公式F(Y1,Y2,Y3,Y4,Y5) = MIN{...} 时间复杂度O(Y1×Y2×Y3×Y4×Y5) 空间复杂度为(Y1×Y2×Y3×Y4×Y5)
*/
for (y5 = 0; y5 <= book[5]; y5++)
{
for (y4 = y5; y4 <= book[4]; y4++)
{
for (y3 = y4; y3 <= book[3]; y3++)
{
for (y2 = y3; y2 <= book[2]; y2++)
{
for (y1 = y2; y1 <= book[1]; y1++)
{
double a[6] = { 0 };//存放不同购书策略所产生的临时数据
int dir[5] = { 0 };//存放下一步策略的Y1 Y2 Y3 Y4 Y5
if (y5 > 0)
{
dir[4] = y5 - 1;
dir[3] = y4 - 1;
dir[2] = y3 - 1;
dir[1] = y2 - 1;
dir[0] = y1 - 1;
sort(dir, dir + 5, greater<int>());//保证Y1>=Y2>=Y3>=Y4>=Y5
a[5] = arr[dir[0]][dir[1]][dir[2]][dir[3]][dir[4]] + discount[5] * bookPrice;
}
if (y4 > 0)
{
dir[4] = y5;
dir[3] = y4 - 1;
dir[2] = y3 - 1;
dir[1] = y2 - 1;
dir[0] = y1 - 1;
sort(dir, dir + 5, greater<int>());
a[4] = arr[dir[0]][dir[1]][dir[2]][dir[3]][dir[4]] + discount[4] * bookPrice;
}
if (y3 > 0)
{
dir[4] = y5;
dir[3] = y4;
dir[2] = y3 - 1;
dir[1] = y2 - 1;
dir[0] = y1 - 1;
sort(dir, dir + 5, greater<int>());
a[3] = arr[dir[0]][dir[1]][dir[2]][dir[3]][dir[4]] + discount[3] * bookPrice;
}
if (y2 > 0)
{
dir[4] = y5;
dir[3] = y4;
dir[2] = y3;
dir[1] = y2 - 1;
dir[0] = y1 - 1;
sort(dir, dir + 5, greater<int>());
a[2] = arr[dir[0]][dir[1]][dir[2]][dir[3]][dir[4]] + discount[2] * bookPrice;
}
if (y1 > 0)
{
dir[4] = y5;
dir[3] = y4;
dir[2] = y3;
dir[1] = y2;
dir[0] = y1 - 1;
sort(dir, dir + 5, greater<int>());
a[1] = arr[dir[0]][dir[1]][dir[2]][dir[3]][dir[4]] + discount[1] * bookPrice;
}
for (int i = 0; i < sizeof(a) / sizeof(double); i++)
{
if ((minDis[y1][y2][y3][y4][y5] > a[i] && a[i]) || minDis[y1][y2][y3][y4][y5] == 0)
minDis[y1][y2][y3][y4][y5] = a[i];//将折扣最大的(即数字最小,但不为0的元素记录在minDIs中)
}
arr[y1][y2][y3][y4][y5] = minDis[y1][y2][y3][y4][y5];//将minDis赋值给arr[y1][y2][y3][y4][y5],下一轮继续使用
}
}
}
}
}
printf("当前购买书本可享有最低的价格为:%.2f", minDis[book[1]][book[2]][book[3]][book[4]][book[5]]);//书本享有的总优惠*书本价格*书本数目/书本数目=书本享有总优惠*书本价格
cout << endl;
system("pause");
return 0;
}
double Min(double a, double b, double c, double d, double e)
{
double n[5] = { a, b, c, d, e };
double minelement = 1000.0;
for (int i = 0; i < 5; i++)
{
if (n[i] < minelement) minelement = n[i];
}
return minelement;
}
double Solve(int x1, int x2, int x3, int x4, int x5)
{
int n[5] = { x1, x2, x3, x4, x5 };
sort(n, n + 5, greater<int>());
x1 = n[0];
x2 = n[1];
x3 = n[2];
x4 = n[3];
x5 = n[4];
if (x5 > 0)
{
return Min(8.0 + Solve(x1 - 1, x2, x3, x4, x5),
2 * 8 * 0.95 + Solve(x1 - 1, x2 - 1, x3, x4, x5),
3 * 8 * 0.9 + Solve(x1 - 1, x2 - 1, x3 - 1, x4, x5),
4 * 8 * 0.8 + Solve(x1 - 1, x2 - 1, x3 - 1, x4 - 1, x5),
5 * 8 * 0.75 + Solve(x1 - 1, x2 - 1, x3 - 1, x4 - 1, x5 - 1));
}
else if (x5 == 0 && x4 > 0)
{
return Min(8.0 + Solve(x1 - 1, x2, x3, x4, x5),
2 * 8 * 0.95 + Solve(x1 - 1, x2 - 1, x3, x4, x5),
3 * 8 * 0.9 + Solve(x1 - 1, x2 - 1, x3 - 1, x4, x5),
4 * 8 * 0.8 + Solve(x1 - 1, x2 - 1, x3 - 1, x4 - 1, x5), INT_MAX);
}
else if (x5 == 0 && x4 == 0 && x3 > 0)
{
return Min(8.0 + Solve(x1 - 1, x2, x3, x4, x5),
2 * 8 * 0.95 + Solve(x1 - 1, x2 - 1, x3, x4, x5),
3 * 8 * 0.9 + Solve(x1 - 1, x2 - 1, x3 - 1, x4, x5),
INT_MAX, INT_MAX);
}
else if (x5 == 0 && x4 == 0 && x3 == 0 && x2 > 0)
{
return Min(8.0 + Solve(x1 - 1, x2, x3, x4, x5),
2 * 8 * 0.95 + Solve(x1 - 1, x2 - 1, x3, x4, x5),
INT_MAX, INT_MAX, INT_MAX);
}
else if (x5 == 0 && x4 == 0 && x3 == 0 && x2 == 0 && x1 > 0)
{
return 8.0*x1;
}
else return 0;
}
int main2()
{
double solution = Solve(2, 2, 2, 1, 1);
cout << solution << endl;
return 0;
}
#endif
//快速找出故障机器
#if 0
class Solution
{
public:
//一台机器故障
int reslove1(vector<int>& nums)
{
if (nums.empty())
{
return -1;
}
unordered_map<int, int> hash_table;
for (int i = 0; i < nums.size(); i++)
{
++hash_table[nums[i]];
}
for (int i = 0; i < nums.size(); i++)
{
if (hash_table[nums[i]] < 2)
return nums[i];
}
return 0;
}
int reslove2(vector<int>& nums)
{
if (nums.empty())
{
return -1;
}
int result = 0;
for (int i = 0; i < nums.size(); i++)
{
result = result ^ nums[i];
}
return result;
}
};
int main()
{
Solution solution;
vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 8, 9 };
int result1 = solution.reslove1(nums);
int result2 = solution.reslove2(nums);
cout << result1 << ";"<< result2 << endl;
return 0;
}
#endif
//饮料供货问题
#if 0
#define INF 0x7fffffff
const int N = 3;//饮料种数
const int V = 8;//水房容量
int C[N + 1] = { 0, 8, 4, 2 }; //Ci表示第i种饮料的容量 (i从1开始)
int H[N + 1] = { 0, 2, 3, 1 }; //H[i]表示第i种饮料的满意度
int dp[N + 1][V + 1]; ///总满意度
//备忘录法
int Cal(int n, int v){
if (n > N){
if (v == 0)
return 0;
else
return -INF;
}
if (v<0)
return -INF;
else if (v == 0)
return 0;
else if (dp[n][v] != -1)
return dp[n][v];
int ret = -INF;
for (int i = 0; i <= V / C[n]; i++){
int temp = Cal(n + 1, v - i*C[n]);
if (temp != -INF){
temp += H[n] * i;
ret = max(ret, temp);
}
}
return dp[n][v] = ret;
}
int main(){
int V = 10;
for (int i = 1; i <= N; i++)
for (int j = 1; j <= V; j++)
dp[i][j] = -1;
cout << Cal(1, V) << endl;
return 0;
}
#endif
#if 0
/*
注意到这个题目的限制,每种饮料容量只能是2的方幂
1)对于总容量V,假设为10,写成2进制形式为,1010,因为每种容量只能是2的方幂,所以对于容量10,也就是等于,
拿8容量的饮料最大值加上拿2容量得饮料的最大值
2)对于相等容量的饮料,当然只用取满意度最高的那种就行了
*/
#define INF 0x7fffffff
const int N = 4;//饮料种数
const int V = 7;//水房容量
struct node{
int C;
int H;
bool operator<(const node &t)const{
return H<t.H;
}
};
node water[N + 1] = { { 0, 0 }, { 8, 4 }, { 4, 3 }, { 4, 2 }, { 2, 1 } };
node *bucket[20][20] = { NULL };
int length[20] = { 0 };
int main(){
//将饮料按照容量进行分类,假设最多20类,如容量为2=2^1,所以将它放到1位置
for (int i = 1; i <= N; i++){
int cnt = 0;
int t = water[i].C;
while (!(t & 1)){
t >>= 1;
cnt++;
}
bucket[cnt][length[cnt]++] = &water[i];
}
//每个类别按照满意度进行排序,选出满意度最高的此类饮料
for (int i = 0; i<20; i++){
if (length[i] == 0)continue;
sort(bucket[i], bucket[i] + length[i]);
}
//store[i]数组存储如要拿2^i容量的饮料所获得的最大满意度
int store[20];
memset(store, -1, sizeof(store));
store[0] = length[0]>0 ? bucket[0][0]->H : -1;
for (int i = 1; i<20; i++){
int t = -1;
if (length[i]>0)t = bucket[i][0]->H;
store[i] = max(t, 2 * store[i - 1]);
if (store[i]>V)break;
}
//将V转化成2进制数据求总满意度
int H = 0;//总满意度
int C = 0;//总容量
int v = V;
int k = 0;
while (v>0){
if (v & 1){
if (store[k]<0){
cout << "无法组成" << (1 << k) << "容量的饮料" << endl;
//break;
}
else {
H += store[k];
C += 1 << k;
}
}
v >>= 1;
k++;
}
cout << "总容量为" << V << endl << "所用容量为" << C << endl << "最大满意度为" << H << endl;
return 0;
}
#endif
#if 0
/**
* W:饮料总容量的最大上限;N:饮料的种类;C:每种饮料的个数;H:每种饮料的满意度;V:每种饮料的容量
* 求:在满足最大容量<=W的前提下,如何购买饮料获得的满意度最大
*/
int Cal(int W, int N, int* C, int* H, int* V)
{
if (W <= 0 || N <= 0 || C == NULL || H == NULL || V == NULL)return 0;
int i, j, k;
int** dp = new int*[N + 1];
for (i = 0; i <= N; i++)
{
dp[i] = new int[W + 1];
}
memset(dp[N], 0, sizeof(int)*(W + 1));
for (i = N - 1; i >= 0; i--)
{
for (j = 1; j <= W; j++)
{
dp[i][j] = 0;
for (k = 0; k <= C[i]; k++)
{
if (j >= k*V[i])
{
dp[i][j] = max(dp[i][j], dp[i + 1][j - k*V[i]] + k*H[i]);
}
else break;
}
}
}
int res = dp[0][W];
for (i = 0; i <= N; i++)delete[] dp[i];
delete[] dp;
return res;
}
int main()
{
int w, n, i;
while (cin >> w >> n)
{
int* C = new int[n];
int* H = new int[n];
int* V = new int[n];
for (i = 0; i<n; i++)
cin >> C[i] >> H[i] >> V[i];
cout << Cal(w, n, C, H, V) << endl;
delete[] C;
delete[] H;
delete[] V;
}
return 0;
}
#endif
//0-1背包问题:每个物品只能拿一个或者不拿
#if 0
const int N = 4; //物品数量
const int C = 7; //背包容量
int w[N] = { 2, 3, 5, 2 }; //w[i]表示第i个物品的容量
int v[N] = { 6, 4, 8, 4 }; //v[i]表示第i个物品的价值
int m[N][C + 1]; //记录子问题的解的表格
int x[N];
void initial()
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j <= C; j++)
{
m[i][j] = -1;
}
}
}
//以下使用备忘录法求解0-1背包问题(物品重量为整型)
int KnapsackMemoMethod(int i, int capacity)
{
if (m[i][capacity] != -1)
return m[i][capacity]; //使用m[i][capacity]需要检查两个下标是否出界
int result = 0;
if (i == N - 1)
{
if (capacity >= w[i])
{
m[i][capacity] = v[i];
return v[i];
}
else
{
m[i][capacity] = 0;
return 0;
}
}
else
{
if (capacity >= w[i])
{
int selected = KnapsackMemoMethod(i + 1, capacity - w[i]) + v[i];
int unselected = KnapsackMemoMethod(i + 1, capacity);
result = selected > unselected ? selected : unselected;
m[i][capacity] = result;
return result;
}
else //capacity < w[i]
{
result = KnapsackMemoMethod(i + 1, capacity);
m[i][capacity] = result;
return result;
}
}
}
void Trace(int i, int capacity)
{
if (i == N - 1)
{
if (m[i][capacity] == v[i])
x[i] = 1;
else
{
x[i] = 0;
}
return;
}
else
{
if (m[i][capacity] == m[i + 1][capacity])
{
x[i] = 0;
Trace(i + 1, capacity);
}
else
{
x[i] = 1;
Trace(i + 1, capacity - w[i]);
}
}
}
int main()
{
initial();
cout << KnapsackMemoMethod(0, C) << endl;
Trace(0, C);
for (int i = 0; i < N; i++)
{
cout << x[i] << " ";
}
cout << endl;
system("pause");
return 0;
}
#endif
#if 0
const int N = 4; //物品数量
const int C = 9; //背包容量
int w[N+1] = {0, 2, 3, 5, 2 }; //w[i]表示第i个物品的容量
int v[N+1] = {0, 6, 4, 8, 4 }; //v[i]表示第i个物品的价值
int m[N+1][C + 1]; //记录子问题的解的表格
int DP_BG(int N,int C)
{
for (int i = 0; i <= N; i++)
{
for (int j = 0; j <= C; j++)
{
m[i][j] = 0;
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 0; j <= C; j++)
{
if (j >= w[i])
{
m[i][j] = max(m[i-1][j], m[i - 1][j - w[i]] + v[i]);
}
else
{
m[i][j] = m[i-1][j];
}
}
}
return m[N][C];
}
int x[N + 1]; //存储最优解的物品选取情况,1表示选取,0表示不选
void trace(int i, int j)
{
if (i < 0) return;
else
{
if (m[i][j] == m[i - 1][j])
{
x[i] = 0;
trace(i - 1, j);
}
else /*if ( j - w[i] >= 0 && m[i][j] = m[i - 1][j] + v[i])*/
{
x[i] = 1;
trace(i - 1, j - w[i]);
}
}
}
int main()
{
int result = DP_BG(N,C);
trace(N, C);
cout << result<< endl;
for (int i = 1; i <= N; i++)
cout << x[i] << " ";
cout << endl;
return 0;
}
#endif
//延伸
#if 0
const int N = 5; //五个物品
const int M = 900; //总共钱数
int v[N + 1] = {0, 300, 500, 600, 400,200 }; //每件物品的价格
int p[N + 1] = { 0, 9, 5, 7, 4 ,3}; //每件物品的价值程度
int maxValue[N+1][M+1]; //最大价值
int DP(int N, int M)
{
for (int i = 0; i <= N; i++) //首先初始化
{
for (int j = 0; j <= M; j++)
{
maxValue[i][j] = 0;
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 0; j <= M; j++)
{
if (j >= v[i])
maxValue[i][j] = max(maxValue[i - 1][j], maxValue[i - 1][j - v[i]] + p[i]);
else
maxValue[i][j] = maxValue[i - 1][j];
}
}
return maxValue[N][M];
}
int x[N+1];
void findWhat(int N, int M)
{
if (N <= 0) return;
else
{
if (maxValue[N][M] == maxValue[N-1][M])
{
x[N] = 0;
findWhat(N - 1, M);
}
else
{
x[N] = 1;
findWhat(N - 1, M - v[N]);
}
}
}
int main()
{
int result = 0;
result = DP(N, M);
cout << result << endl;
findWhat(N,M);
for (int i = 1; i <= N; i++)
{
cout << x[i] << " ";
}
cout<<endl;
}
#endif
//硬币问题
#if 0
#define INF 100000000
#define MAXNUM 10000
#define MONEYKIND 100
int n, S;
int V[MONEYKIND];
int MIN[MAXNUM], MAX[MAXNUM];
void dp(int*, int*);
//递推方法函数声明
void print_ans(int*, int);
//输出函数声明
int main()
{
int i;
printf("输入硬币的种数n(1-100):\n");
scanf("%d", &n);
printf("输入要组合的钱数S(0-10000):\n");
scanf("%d", &S);
printf("输入硬币种类:\n");
for (i = 1; i <= n; i++)
{
scanf("%d", &V[i]);
}
dp(MIN, MAX);
printf("最小组合方案:\n");
print_ans(MIN, S);
printf("\n");
printf("最大组合方案:\n");
print_ans(MAX, S);
return 0;
}
void dp(int *min, int *max)
//递推过程实现
{
int i, j;
min[0] = max[0] = 0;
for (i = 1; i <= S; 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 - V[j]] + 1<min[i]){
min[i] = min[i - V[j]] + 1;//最小组合过程
}
if (max[i - V[j]] + 1>max[i])
max[i] = max[i - V[j]] + 1;//最大组合过程
}
cout << *min_element(max + 1, max + S + 1) << endl; //最小组合的硬币数量
cout << *max_element(max + 1, max + S + 1) << endl; //最大组合的硬币数量
}
void print_ans(int *d, int S)
//输出函数实现
{
int i;
for (i = 1; i <= n; i++)
if (S >= V[i] && d[S] == d[S - V[i]] + 1)
{
cout << V[i] << " ";
print_ans(d, S - V[i]);
break;
}
}
#endif
#if 0
const int N = 4;
const int C = 7;
int w[N + 1] = {0,2,3,5,2};
int v[N + 1] = {0,6,4,8,4};
int m[N + 1][C + 1];//记录子问题
int x[N + 1];
void initial()
{
for (int i = 0; i <= N; i++)
{
for (int j = 0; j <= C; j++)
{
m[i][j] = -1;
}
}
}
int KnapsackMemoMethod(int i, int capacity)
{
if (m[i][capacity] != -1) return m[i][capacity];
if (i == N)
{
if (capacity >= w[i])
{
m[i][capacity] = v[i];
return v[i];
}
else
{
m[i][capacity] = 0;
return 0;
}
}
else
{
if (capacity >= w[i])
{
int selected = v[i] + KnapsackMemoMethod(i+1,capacity - w[i]);
int unselected = KnapsackMemoMethod(i + 1, capacity);
m[i][capacity] = max(selected,unselected);
return m[i][capacity];
}
else
{
m[i][capacity] = KnapsackMemoMethod(i + 1, capacity);
return m[i][capacity];
}
}
}
void Trace(int i, int capacity)
{
if (i == N)
{
if (m[i][capacity] == v[i])
x[i] = 1;
else
x[i] = 0;
}
else
{
if (m[i][capacity] == m[i + 1][capacity])
{
x[i] = 0;
Trace(i + 1, capacity);
}
else
{
x[i] = 1;
Trace(i + 1, capacity - w[i]);
}
}
}
int main()
{
initial();
cout << KnapsackMemoMethod(1, C) << endl;
Trace(1, C);
for (int i = 1; i <= N; i++)
{
cout << x[i] << " ";
}
cout << endl;
system("pause");
return 0;
}
#endif
//导弹拦截问题
#if 0
void intercept()
{
vector<int> missile = { 389, 207, 155, 300, 299, 170, 158, 65 };
int len = missile.size();
vector<int> note(len);
for (int i = 0; i < len; i++)
note[i] = 0;//note表初始化
for (int i = len - 1; i >= 0; i--)//从最后一个导弹开始向前分析
{
int max = 0, flag = i;//max表示向后查询记录表note时,当前查询到的最多可拦截导弹数量,flag表示当前查到的最大数量导弹的下标
cout << "i=" << i << endl;
for (int j = i + 1; j < len; j++)
{
if (missile[i] > missile[j] && note[j] > max)//当当前导弹高度大于之后第j个导弹高度,且第j个导弹之后可拦截最多数量大于目前已知最大数量时候,更新flag和max;
{
flag = j;
max = note[j];
}
}
note[i] = note[flag] + 1;
for (auto x : note)
cout << x << " ";
cout << endl;
}
return;
}
int main()
{
intercept();
return 0;
}
#endif
//切钢条问题
#if 0
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
int main()
{
vector<int> table = { 0, 1, 5, 8, 9, 10, 17, 17, 20, 24, 30 };//方便理解,数组下标从1开始,0补位 C++11新标准vector初始化方式
int n;
cin >> n;//输入钢条长度
vector<int> r(n + 1, 0);//方便理解,数组下标从1开始,初始化11位数组
for (int i = 1; i <= n; i++)
{
int max = -1;
for (int j = 1; j <= i; j++)
{
if (max < table[j] + r[i - j])
max = table[j] + r[i - j];
}
r[i] = max;
}
for (auto x : r)
cout << x << " ";
cout << endl;
return 0;
}
#endif
动态规划实例
猜你喜欢
转载自blog.csdn.net/sinat_36412790/article/details/80416722
今日推荐
周排行