- 实验目的与要求
熟悉C/C++语言的集成开发环境;
通过本实验加深对分治法、贪心算法的理解。
- 实验内容:
掌握分治法、贪心算法的概念和基本思想,并结合具体的问题学习如何用相应策略进行求解的方法。
- 实验题
1. 【伪造硬币问题】给你一个装有n个硬币的袋子。n个硬币中有一个是伪造的。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。试用分治法的思想写出解决问题的算法,并计算其时间复杂度。
#include<iostream>
using namespace std;
int find_fake(int a[],int low,int high)
{
int sum1, sum2, sum3;
sum1 = sum2 = sum3 = 0;
int fake=0;
if (low + 1 == high)
{
if (a[low] < a[high])
{
fake = low;
return fake;
}
else
{
fake = high;
return fake;
}
}
if ((high - low + 1) % 2 == 0)//偶数个
{
int mid = low + (high - low + 1) / 2 - 1;
for (int i = low;i <= mid;i++)
{
sum1 += a[i];
}
for (int i = mid+1 ;i <= high;i++)
{
sum2 += a[i];
}
if (sum1 < sum2)
{
fake = find_fake(a, low, mid);
return fake;
}
if (sum1 > sum2)
{
fake = find_fake(a, mid+1, high);
return fake;
}
}
else //当长度为奇数的时候
{
int mid = low + (high - low) / 2 ;
for (int i = low;i <=mid-1;i++) //对前半段求和
{
sum1 += a[i];
}
for (int i = mid+1;i <= high;i++)//对后半段求和
{
sum2 += a[i];
}
sum3 = a[low + (high - low) / 2]; //sum3用于存放中间数据
if (sum1 < sum2) //假币在前半段
{
fake = find_fake(a, low, mid-1);
return fake;
}
else if (sum1 > sum2)
{
fake = find_fake(a, mid, high);
return fake;
}
else if (sum1 + sum3 == sum2 + sum3) //中间的那个就是假币
{
fake = (high - low) / 2 + 1;
return fake;
}
}
}
int main()
{
int n=0;
int fake = 0;
cout << "请输入硬币总数n:";
cin >> n;
int* a = new int[n+1];
cout << "请依次输入硬币的重量:";
for (int i = 1;i <= n;i++)
{
cin >> a[i];
}
fake=find_fake(a, 1, n);
cout << "第" << fake << "枚硬币是假的。" << endl;
}
2.【找零钱问题】一个小孩买了价值为33美分的糖,并将1美元的钱交给售货员。售货员希望用数目最少的硬币找给小孩。假设提供了数目有限的面值为25美分、10美分、5美分、及1美分的硬币。给出一种找零钱的贪心算法。
#include<iostream>
using namespace std;
void getmax(int& x)
{
int m=0;
int record[4] = { 0 };
while (x >= 25)
{
record[3]++;
x -= 25;
}
while (x >= 10)
{
record[2]++;
x -= 10;
}
while (x >= 5)
{
record[1]++;
x -= 5;
}
while (x >= 1)
{
record[0]++;
x -= 1;
}
cout << "需要找回" << record[3] << "张25美分," << record[2] << "张10美分," << record[1] << "张5美分," << record[0] << "张1美分。";
}
int main()
{
int prise = 0;
int give = 0;
cout << "请问商品的原价为:";
cin >> prise;
cout << endl;
cout << "请问顾客付款为:";
cin >> give;
cout << endl;
int back = give - prise;
getmax(back);
}
算法实现二
- 实验目的与要求
熟悉C/C++语言的集成开发环境;
通过本实验加深对贪心算法、动态规划和回溯算法的理解。
- 实验内容:
掌握贪心算法、动态规划和回溯算法的概念和基本思想,分析并掌握"0-1"背包问题的三种算法,并分析其优缺点。
- "0-1"背包问题的贪心算法
-
#include<iostream> using namespace std; struct things { int value; int weight; }; int main() { int n = 0;//物品总数 int c = 0;//背包容量 cout << "请输入物品总数n:"; cin >> n; cout << "请输入背包容量:"; cin >> c; things* t = new things[n]; for (int i = 0;i < n;i++) { cout << "请依次输入第" << i + 1 << "件物品的价值、重量:"; cin >> t[i].value >> t[i].weight; } for (int i = 0;i < n;i++) { for (int j = 0;j < n - 1;j++) { if ((t[i].value / t[i].weight) < (t[i + 1].value / t[i + 1].weight)) { things temp = t[i]; t[i] = t[i + 1]; t[i + 1] = temp; } } } //贪心算法 int weight_sum = 0; int vaule_sum = 0; int k = 0; while (weight_sum < c && k < n) { if (weight_sum + t[k].weight <= c) { weight_sum += t[k].weight; vaule_sum += t[k].value; } k++; } cout << "一共装入了价值为" << vaule_sum << "的物品。" << endl; }
- "0-1"背包问题的动态规划算法
-
#include<iostream> #include<iomanip> using namespace std; int main() { int n = 0;//物品总数 int c = 0;//背包容量 cout << "请输入物品总数n:"; cin >> n; cout << "请输入背包容量:"; cin >> c; int* value = new int[n]; int* weight = new int[n]; for (int i = 0;i < n;i++) { cout << "请依次输入第" << i + 1 << "件物品的价值、重量:"; cin >> value[i] >> weight[i]; } int** maxValue = new int*[n]; for (int i = 0;i < n;i++) { maxValue[i] = new int[c]; } for (int i = 0;i < n;i++) { for (int j = 0;j < c;j++) { maxValue[i][j] = 0; } } //填充表格 for (int i = 0;i < n;i++) { for (int j = 1;j <= c;j++) { if (i == 0) { maxValue[i][j - 1] = (weight[i] <= j ? value[i] : 0); } else { int topValue = maxValue[i - 1][j - 1];//上一个值 int nowValue = (weight[i] <= j ? (j - weight[i] > 0 ? value[i] + maxValue[i - 1][j - weight[i]-1] : value[i]) : topValue);//比较重量 maxValue[i][j - 1] = (topValue > nowValue ? topValue : nowValue); } } } for (int i = 0;i < n;i++) { for (int j = 0;j < c;j++) { cout << setw(7) << maxValue[i][j] ; } cout << endl; } cout << "背包能装入的最大价值为:" << maxValue[n-1][c-1]; }
- "0-1"背包问题的回溯算法
#include<iostream>
#include<cmath>
using namespace std;
struct things
{
int judge;
int value;
int weight;
};
int maxv = 0;
void backtrace(things t[],int c,int now,int &max,int n)
{
static int w = 0;
static int v = 0;
if (now+1 == n)
{
if (v > max && w <= c)
{
max = v;
maxv = max;
}
return;
}
//没有背该物品
backtrace(t, c, now + 1, max, n);
//背了
w += t[now].weight;
v += t[now].value;
backtrace(t, c, now + 1, max, n);
w -= t[now].weight;
v -= t[now].value;
}
int main()
{
int n = 0;//物品总数
int c = 0;//背包容量
cout << "请输入物品总数n:";
cin >> n;
cout << "请输入背包容量:";
cin >> c;
int max = 0;
things* t = new things[n];
for (int i = 0;i < n;i++)
{
cout << "请依次输入第" << i + 1 << "件物品的价值、重量:";
cin >> t[i].value>>t[i].weight;
}
for (int i = 0;i < n;i++) //排序
{
for (int j = 0;j < n - 1;j++)
{
if ((t[i].value / t[i].weight) < (t[i + 1].value / t[i + 1].weight))
{
things temp = t[i];
t[i] = t[i + 1];
t[i + 1] = temp;
}
}
}
backtrace(t, c, 0 ,max, n);
cout << "一共背入价值为" << maxv << "的物品";
}