递归
例题2->Hanoi塔
#include<iostream>
using namespace std;
void Move(char a, char b)
{
cout << a << "->" << b << endl;
}
void Hanoi(int n, char a, char b, char c)
{
if (n == 1)
Move(a, c);
else
{
Hanoi(n - 1, a, c, b);//将A座上的n-1个盘子借助C座移向B座
Move(a, c);//将A座上最后一个盘子移向C座
Hanoi(n - 1, b, a, c);//将B座上的n-1个盘子借助A座移向C座
}
}
int main()
{
int n;
cout<< "input how many plates:";
cin >> n;//输入共有几个待移动盘子
Hanoi(n, 'a', 'b', 'c');
}
例题3->N皇后
#include<iostream>
#include<cmath>
using namespace std;
int QueenPos[100];
int N;//N是递归中的一个变量所以要定义在全局变量中
int Terms;//Terms是递归中的一个变量所以要定义在全局变量中
void Nqueen(int n)
{
if (n == N)//当摆放好的皇后数与总的皇后数一样时,则证明现在有一种可行的方案,输出
{
for (int i = 0; i < N; i++)
cout << i << ":" << QueenPos[i]<<" ";
cout << endl;
Terms++;//计数共有几种可行的方案
return;
}
for (int i = 0; i < N; i++)//逐个试探第n个皇后的位置,从0~N
{
int j;
for (j = 0; j < n; j++)//检查若第n个皇后在第i个位置会不会与前n个皇后中的某个冲突
{
if (QueenPos[j] == i || abs(QueenPos[j] - i) == n - j)
{
break;//若冲突,退出此循环
}
}
if (n == j)//若成立则说明此皇后所在位置符合要求
{
QueenPos[n] = i;
Nqueen(n + 1);//为下一个皇后分配位置
}
}
}
int main()
{
cout << "input how many queens:";
cin >> N;
Nqueen(0);
cout << Terms << " available configurations" << endl;
}
例题4->逆波兰表达式
#include<iostream>
#include<cstdlib>
using namespace std;
int Exp()
{
char ch[100];
cin >> ch;
switch (ch[0])
{
case '+': return Exp() + Exp();
case '-': return Exp() - Exp();
case '*': return Exp() * Exp();
case '/': return Exp() / Exp();
default : return atoi(ch);//将字符串型转变为整数型
break;
}
}
int main()
{
cout << Exp() << endl;
}
补充知识:
在C++的cstdlib中,除了atof()
之外,还有其他几个与字符串到数值转换相关的函数。这些函数包括:
atoi()
: 将字符串转换为整数(int
)。atol()
: 将字符串转换为长整数(long
)。atoll()
: 将字符串转换为长长整数(long long
),这个函数在C99标准中引入。atof()
: 将字符串转换为浮点数(double
)。
例题5->表达式
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int Factor_Value();
int Term_Value();
int Expression_Value();
int Expression_Value()//处理整个表达式中的=-运算
{
int Res = Term_Value();//先计算表达式中的项(如果有的话)
bool more = 1;
while (more)
{
char Ini = cin.peek();//从现存的表达式中提取第一个因子(符号)
if (Ini == '+' || Ini == '-')//通过刚才判断的符号判断接下来还有没有项
{
cin.get();//舍弃刚刚用来判断的‘+’或‘-’
int Leftover = Term_Value();//对这个项进行计算
if (Ini == '+')//将上述得到的两项计算
Res += Leftover;
else
Res -= Leftover;
}
else
more = 0;
}
return Res;
}
int Term_Value()//处理表达式中的项,即(a*/b)
{
int Res = Factor_Value();//判断这项的第一个因子
while (1)
{
char Ini = cin.peek();//从现存的表达式中提取第一个因子(符号)
if (Ini == '*' || Ini == '/')//通过刚才判断的符号判断接下来还有没有需要运算的因子
{
cin.get();
int Leftover = Factor_Value();
if (Ini == '*')
Res *= Leftover;
else
Res /= Leftover;
}
else
break;
}
return Res;
}
int Factor_Value()//处理每一个因子并且计算最后的值
{
int Res = 0;
char ch = cin.peek();
if (ch == '(')//如果当前表达式第一个因子为'(',说明此时需要计算一个子表达式
{
cin.get();//舍弃此'(‘
Res = Expression_Value();//返回计算这个子表达式
cin.get();//舍弃遗存的')'
}
else
{
while (isdigit(ch))
{
Res = 10 * Res + ch - '0';//计算最终结果,说明:数字的ascii-0的ascii即是这个数
cin.get();
ch = cin.peek();
}
}
return Res;
}
int main()
{
cout << Expression_Value() << endl;
}
补充知识:
cin.get()
是 C++ 中用于从输入流 cin
中读取一个字符的函数。它的作用类似于 cin >>
操作符,但是不同之处在于 cin.get()
可以读取输入流中的任何字符,包括空格、制表符甚至换行符,而不会像 >>
操作符一样被空白字符忽略。
cin.peek()
是 C++ 中用于查看输入流 cin
中下一个字符的函数。它的作用是返回输入流中下一个字符的值,但不会从输入流中移除该字符,也不会导致程序执行在字符上停止。这意味着可以使用 cin.peek()
来查看下一个字符,然后决定如何处理输入,而不会影响后续的输入操作。
关于几个判断函数:
isalpha(c)
:检查字符c
是否是字母(a-z 或 A-Z)。isdigit(c)
:检查字符c
是否是数字字符(0-9)。isalnum(c)
:检查字符c
是否是字母或数字字符。islower(c)
:检查字符c
是否是小写字母。isupper(c)
:检查字符c
是否是大写字母。isspace(c)
:检查字符c
是否是空白字符(空格、制表符、换行符等)。ispunct(c)
:检查字符c
是否是标点符号。isxdigit(c)
:检查字符c
是否是十六进制数字(0-9、a-f、A-F)。
例题6->爬楼梯
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int Stairs(int N)
{
if (N < 0)//边界条件
return 0;
else if (N == 0)//边界条件
return 1;
else
return Stairs(N - 1) + Stairs(N - 2);
}
int main()
{
int N;
cin >> N;
cout << "爬楼梯有" << Stairs(N) << "方式" << endl;
}
例题7->分苹果(待修改)
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int Apples(int m, int n)
{
if (m < n)//边界条件
return Apples(m, m);
else if (n == 0)//边界条件
return 0;
else if (m == 0)
return 1;
else
return Apples(m, n - 1) + Apples(m - n, n);
}
int main()
{
int m, n;
cin >> m >> n;
cout << "total " << Apples(m, n) << " ways to allocate the apples" << endl;
}
例题8->算24
#include<iostream>
using namespace std;
#define EPS 1e-6//由于浮点数之间的是否相等比较不能用 a==b 这种方法来判断,所以需要加一个极小值来充当判断条件
bool IsZero(double x)//判断某个数是否为0(x即为两个浮点数相减的结果)
{
return fabs(x) <= EPS;
}
bool Count24(double Arr[], int n)
{
if (n == 1)//当Arr[]中只剩下一个值才能进入最终的判断条件
{
if (IsZero(Arr[0] - 24))//最终的判断的条件,最后计算的只会剩下一个值,即Arr[0]
return 1;
else
return 0;
}
double arr[4];//定义一个用来拷贝Arr[]值的数组
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)//二重循环为了枚举所有的2个取值
{
int flag = 0;//arr[]的计数器
for (int k = 0; k < n; k++)//这个循环是为了先将Arr[]中的剩下的值存到arr[]中
{
if (k != i && k != j)
{
arr[flag++] = Arr[k];
}
}
arr[flag] = Arr[i] + Arr[j];//将从arr[]枚举出来的两个值进行各种运算,然后存到arr[]中
if (Count24(arr, n - 1))
return 1;
arr[flag] = Arr[i] - Arr[j];
if (Count24(arr, n - 1))
return 1;
arr[flag] = Arr[j] - Arr[i];
if (Count24(arr, n - 1))
return 1;
arr[flag] = Arr[i] * Arr[j];
if (Count24(arr, n - 1))
return 1;
if (!IsZero(Arr[j]))//判断除数是否为0
{
arr[flag] = Arr[i] / Arr[j];
if (Count24(arr, n - 1))
return 1;
}
if (!IsZero(Arr[i]))
{
arr[flag] = Arr[j] / Arr[i];
if (Count24(arr, n - 1))
return 1;
}
}
}
return 0;//若直到最后都没有符合条件,那么什么没有符合的值
}
int main()
{
double Arr[4];
for (int i = 0; i < 4; i++)
cin >> Arr[i];
if (Count24(Arr, 4))
cout << "solution exists" << endl;
else
cout << "solution not exists" << endl;
}
划重点:由于浮点数之间的是否相等比较不能用 a==b 这种方法来判断,所以需要加一个极小值EPS来充当判断条件,即通过判断fabs(a-b)是否小于EPS.
二分算法
例题1->二分查找
#include <iostream>
using namespace std;
void BinarySearch(int n)
{
int Arr[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int low = 0;
int high = sizeof(Arr) / sizeof(int) - 1;
if (cin.fail()) {
cout << "Invalid input. Please input a valid number." << endl;
return;
}
while (low <= high) {
int mid = low + (high - low) / 2;
if (Arr[mid] < n)
low = mid + 1;
else if (Arr[mid] > n)
high = mid - 1;
else {
cout << "Found it! Index is " << mid << endl;
return;
}
}
cout << "No such number." << endl;
}
int main()
{
int n;
cout << "Input the number you want to find: ";
cin >> n;
BinarySearch(n);
return 0;
}
补充知识:
cin.fail()
是C++中用于检查输入流的状态的函数。当使用 cin
进行输入时,如果输入的数据类型与预期不符或者输入过程中发生错误,cin.fail()
函数将返回 true,表示输入流处于错误状态。通常,它用于检查用户输入了非预期的数据类型,比如当用户输入了一个字母而不是数字。当 cin.fail()
返回 true 时,你就可以处理输入错误的情况,比如清空输入流、提示用户重新输入等。
例题2->二分法求方程的根
#include <iostream>
using namespace std;
#define EPS 1e-6
bool IsZero(double x)//判断是否达到精确值
{
return fabs(x) <= EPS;
}
double Func(double x)//计算函数值
{
return x * x * x - 5 * x * x + 10 * x - 80;
}
void Root()
{
double x1 = 0, x2 = 100, mid;//在0~100的定义域内进行逼近
int flag = 0;//计数进行了几次逼近
while (1)
{
flag++;
mid = (x1 + x2) / 2;
if (IsZero(Func(mid)))//已经逼近到精确值,退出循环
break;
else if (Func(mid) > EPS)//理解为此时函数值大于0,右值向左移动
x2 = mid;
else//相反左值向右移动
x1 = mid;
}
cout << mid << " is the root with " << flag << " times binary search" << endl;
}
int main()
{
Root();
}
例题3->找一对数
#include <iostream>
using namespace std;
#define TOTAL 66//规定两个数之和为66
void Pair()
{
int Arr[20] = { 0, 10, 12, 17, 19, 25, 28, 31, 35, 42, 49, 51, 57, 60, 66, 73, 83, 88, 94, 95 };
int another, low, high, mid;
for (int i = 0;i < 20; i++)//先遍历第一个值
{
another = TOTAL - Arr[i];//算出第二个值作为下面二分查找的目标
low = 0;
high = 19;
while (low <= high)
{
mid = low + (high - low) / 2;
if (another < Arr[mid])
high = mid - 1;
else if (another > Arr[mid])
low = mid + 1;
else
{
cout << "find it:" << Arr[mid] << " and " << Arr[i] << endl;
return;
}
}
}
cout << "can not find matching number" << endl;
}
int main()
{
Pair();
}
例题4->农夫与奶牛(待补)
分治
例题1->归并排序
#include <iostream>
using namespace std;
int Arr[20] = { 57, 12, 35, 88, 42, 66, 19, 73, 25, 51, 94, 17, 60, 7, 49, 10, 31, 83, 28, 95 };
int Temp[20] = {0};//拷贝数组,存放临时的排序后的数组内容
void Merge(int Arr[], int s, int m, int e, int Temp[])
{
int p1 = s, p2 = m + 1, p = 0;
while (p1 <= m && p2 <= e)
{
if (Arr[p1] < Arr[p2])//按照大小依次将第一个或者第二个数组的值放入Arr[]中
Temp[p++] = Arr[p1++];
else if (Arr[p1] > Arr[p2])
Temp[p++] = Arr[p2++];
}
while (p1 <= m)//如果第一个子数组还有内容而第二个子数组没有内容,则把第一个子数组中的剩下的值依次放入Temp[]中
Temp[p++] = Arr[p1++];
while (p2 <= e)
Temp[p++] = Arr[p2++];
for (int i = s; i <= e; i++)//把排好序的两个子数组放回原来的数组的对应位置
{
Arr[i] = Temp[i - s];
}
}
void MergeSort(int Arr[], int s, int e, int Temp[])//用来细分从s到e的这段数组,用Merge()函数来排序然后合并细分后的小数组
{
int m = 0;
if (s < e)
{
m = s + (e - s) / 2;//分隔数组为两个子数组
MergeSort(Arr, s, m, Temp);//两个子数组再重复递归分为更小的子数组
MergeSort(Arr, m + 1, e, Temp);
Merge(Arr, s, m, e, Temp);//排序,合并各级子数组
}
}
int main()
{
int s, e;
cout << "input start and end point:";
cin >> s >> e;
MergeSort(Arr, s, e, Temp);
for (int i = s; i <= e; i++)
cout << Arr[i] << " ";
}
例题2->快速排序
#include <iostream>
using namespace std;
int Arr[20] = { 57, 12, 35, 88, 42, 66, 19, 73, 25, 51, 94, 17, 60, 7, 49, 10, 31, 83, 28, 95 };
void Swap(int& a, int& b)//用于在快速排序中的交换两值操作
{
int temp = a;
a = b;
b = temp;
}
void QuickSort(int s, int e)
{
if (s >= e)//若起始点大于等于终止点,则返回
return;
if (cin.fail())//若输出不正确,返回
cout << "invaild input" << endl;
int low = s, temp = Arr[low], high = e;
while (low != high)//运行到最后一定有low=high
{
if (high > low && Arr[high] > temp)//先从temp的右边向左边搬运小于temp的值
high--;//若temp右边的值仍然大于temp,则high指针向左移动
Swap(Arr[low], Arr[high]);//发现有右边的值小于temp的值,则交换
if (high > low && Arr[low] < temp)//只后从temp的左边向右边搬运小于temp的值
low++;//若temp左边的值仍然小于temp,则high指针向右移动
Swap(Arr[high], Arr[low]);//发现有左边的值大于temp的值,则交换
}
QuickSort(s, low - 1);//递归在当前temp的左边进行重复的交换操作
QuickSort(low + 1, e);
}
int main()
{
int s, e;
cout << "input start and end:";
cin >> s >> e;//输入起始点和终止点
QuickSort(s, e);
for (int i = s; i <= e; i++)
cout << Arr[i] << " ";
}
动态规划
例题1->数字三角形(1)
#include <iostream>
using namespace std;
int Dis[6][6] =
{
{1, 0, 0, 0, 0, 0},
{7, 8, 0, 0, 0, 0},
{13, 14, 15, 0, 0, 0},
{19, 20, 21, 22, 0, 0},
{25, 26, 27, 28, 29, 0},
{31, 32, 33, 34, 35, 36}
};
int Max[6][6];
int FindMax(int i, int j)
{
if (Max[i][j] != -1)//此处即是动态规划的体现,每次将已经计算好的Max值存起来,不用再次计算,大大的减少了计算
return Max[i][j];
if (i == 6)//若计算到最后一行,则返回本身的值
Max[i][j] = Dis[i][j];
else
Max[i][j] = max(FindMax(i + 1, j), FindMax(i + 1, j + 1)) + Dis[i][j];//否则在左下或右下值中选择一个较大的
return Max[i][j];
}
int main()
{
for (int i = 0; i < 6; i++)
for (int j = 0; j <= i; j++)
Max[i][j] = -1;
cout << "the max distance is " << FindMax(0, 0) << endl;
}
例题2->数字三角形(2)
#include <iostream>
using namespace std;
int Dis[6][6] =
{
{1, 0, 0, 0, 0, 0},
{7, 8, 0, 0, 0, 0},
{13, 14, 15, 0, 0, 0},
{19, 20, 21, 22, 0, 0},
{25, 26, 27, 28, 29, 0},
{31, 32, 33, 34, 35, 36}
};
int FindMax(int i, int j)
{
for (int i = 4; i >= 0; i--)
for (int j = 0; j <= i; j++)
Dis[i][j] = max(Dis[i + 1][j], Dis[i + 1][j + 1]) + Dis[i][j];
return Dis[0][0];
}
int main()
{
cout << "the max distance is " << FindMax(0, 0) << endl;
}
例题3->最长上升子序列
#include <iostream>
using namespace std;
int Arr[6];
int GetMax(int MaxLen[])
{
int temp = MaxLen[0];
for (int i = 0; i < 6; i++)
{
if (MaxLen[i] > temp)
{
temp = MaxLen[i];
}
}
return temp;
}
void MaxArray(int Arr[])
{
int MaxLen[6];
for (int i = 0; i < 6; i++)
{
cout << "input data:";
cin >> Arr[i];
MaxLen[i] = 1;
}
for (int i = 1; i < 6; i++)//为MaxLen数组赋值
{
for (int j = 0; j < i; j++)//通过遍历i之前的值,看看当前Arr[i]是否大于前面的所有值
{
if (Arr[i] > Arr[j])//如果是,则将新值写入MaxLen[]中
{
MaxLen[i] = max(MaxLen[i], MaxLen[j] + 1);//如果Arr[i]也是当前最大递增序列中的,则MaxLen[i]是上一个最大递增序列的MaxLen+1
}
}
}
cout << "Max length is " << GetMax(MaxLen);
}
int main()
{
MaxArray(Arr);
}
例题4->最长公共子序列(待补)
例题5->最佳加法表达式(待补)
例题6->help jimmy(待改)
#include <iostream>
#include<limits>
using namespace std;
#define MAXHEIGHT 3
#define MAXTIME numeric_limits<double>::max()
#define MAX 100
struct Point
{
int h;
int x;
}p[3];
int Time[10][10];
int LJump(int s, int e);
int RJump(int s, int e);
int LJump(int s, int e)
{
if (e == 2)
{
if (p[2].h >= MAXHEIGHT)
return MAXTIME;
else
return p[2].h;
}
else
{
for (int i = s; i < 3; i++)
{
if (p[s].h - p[i].h < MAXHEIGHT)
{
if (Time[s][e] != -1)
return Time[s][e];
else
{
Time[s][e] = p[s].h - p[e].h + min(LJump(e, i) + p[e].x - p[i].x, RJump(e, i) + p[i].x - p[e].x);
return Time[s][e];
}
}
}
}
}
int RJump(int s, int e)
{
if (e == 2)
{
if (p[2].h >= MAXHEIGHT)
return MAXTIME;
else
return p[2].h;
}
else
{
for (int i = s; i < 3; i++)
{
if (p[s].h - p[i].h < MAXHEIGHT)
{
if (Time[s][e] != -1)
return Time[s][e];
else
{
Time[s][e] = p[s].h - p[e].h + min(LJump(e, i) + p[e].x - p[i].x, RJump(e, i) + p[i].x - p[e].x);
return Time[s][e];
}
}
}
}
}
int main()
{
memset(Time, -1, sizeof(Time));
for (int i = 0; i < 3; i++)
{
cout << "input h and x:";
cin >> p[i].h >> p[i].x;
}
cout << LJump(0, 1) << endl;
}
例题7->滑雪
#include <iostream>
using namespace std;
int Terr[5][5] =
{
{1, 2, 3, 4, 5},
{16, 17, 18, 19, 6},
{15, 24, 25, 20, 7},
{14, 23, 22, 21, 8},
{13, 12, 11, 10, 9}
};
void Ski(int l[5][5])
{
for (int i = 0; i < 5; i++)//循环地图每一个点
{
for (int j = 0; j < 5; j++)
{
if (i - 1 >= 0 && i + 1 <= 5 && j - 1 >= 0 && j + 1 <= 5)//避免越界
{
if (Terr[i - 1][j] > Terr[i][j])//检查每个点四周的高低情况
{
l[i - 1][j] = max(l[i - 1][j], l[i][j] + 1);//若四周有点位置比当前点高,此时有两种情况
}//1:更新四周点的最远距离,即+1 2:该四周点当前最远滑雪距离与前者相比更远,无需更新
if (Terr[i + 1][j] > Terr[i][j])
{
l[i + 1][j] = max(l[i + 1][j], l[i][j] + 1);
}
if (Terr[i][j - 1] > Terr[i][j])
{
l[i][j - 1] = max(l[i][j - 1], l[i][j] + 1);
}
if (Terr[i][j + 1] > Terr[i][j])
{
l[i][j + 1] = max(l[i][j + 1], l[i][j] + 1);
}
}
}
}
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 5; j++)
{
cout << l[i][j] << " ";
}
cout << endl;
}
}
int main()
{
int l[5][5];
for (int i = 0; i < 5; i++)//将每个点可以滑雪的最长路径置为1
for (int j = 0; j < 5; j++)
l[i][j] = 1;
Ski(l);
}
例题8->神奇的口袋
#include <iostream>
using namespace std;
int good[20] = { 3, 11, 7, 0, 14, 9, 16, 5, 10, 2, 8, 1, 12, 4, 15, 6, 13, 10, 0, 9 };
void Weight()
{
int Ways[21][41];//Ways[x][y]:从前x个物品里面找质量为y的方法数
memset(Ways, 0, sizeof(Ways));//所有方法数置为0
for (int i = 0; i < 21; i++)
Ways[i][0] = 1;//前x个物品里面找质量为0的方法数有1个
for (int i = 1; i < 41; i++)
{
for (int j = 1; j < 21; j++)
{
Ways[j][i] = Ways[j - 1][i];//前j个物品里面找质量为i的方法数首先包含:前j-1个物品里面找质量为i的方法数
//注意此时方法数里面不包含第j个物品
if (i >= good[j])//若方法数里面可以包含第i个物品(因为第j个物品可能质量大于i)
Ways[j][i] += Ways[j - 1][i - good[j]];//包含第j个物品,那么还要填充i-good[j]质量的物品
//填充余下质量的方法数即是包含第j个物品时达到质量i的方法数
}
}
cout << "total " << Ways[20][40] << " ways" << endl;
}
int main()
{
Weight();
}
补充知识:在C++中,memset()
函数通常用于将一块内存的内容设置为指定的值。一般情况下,不建议直接在C++中使用memset()
来处理数组越界的情况,因为memset()
主要用于设置内存块的连续值,而不对数组进行越界检查。
函数原型如下:void *memset(void *str, int c, size_t n);
例题9->0-1背包问题(待优化)
#include <iostream>
using namespace std;
struct Good
{
int Value;
int Volume;
}good[11];
void MaxValue(Good good[])
{
int value[11][51];
memset(value, 0, sizeof(value));
for (int j = 1; j < 51; j++)//先为value[1][j]取边界值
{
if (good[1].Volume > j)//若第一个物品的体积大于j体积,说明放不进去,所以前1个物品不超过体积j的最大价值为0
value[1][j] = 0;
else//否则为第一个物品的价值
value[1][j] = good[1].Value;
}
for (int i = 1; i < 11; i++)
{
for (int j = 1; j < 51; j++)
{
if (good[i].Volume > j)//若第i个物品的体积大于j,则说明前i个物品的不超过体积j的最大加价值为前i-1个物品的
value[i][j] = value[i - 1][j];
else//否则判断是带第i个物品的最佳价值高还是不带的价值高
value[i][j] = max(value[i - 1][j], value[i - 1][j - good[i].Volume] + good[i].Value);
}
}
cout << "max value is " << value[10][50];
}
int main()
{
for (int i = 1; i < 11; i++)
{
good[i].Value = pow((i + 1), 2) - i * 3;
good[i].Volume = pow((i + 2), 2) - i * 6;
}
MaxValue(good);
}
例题10->方盒游戏(待补)
#include <iostream>
#include<string>
using namespace std;
const int n = 3;
int Score[n][n][n];
struct Segment
{
int Color;
int Len;
}seg[n];
int Game(int s, int e, int len)
{
if (Score[s][e][len] != -1)
return Score[s][e][len];
int res = pow(seg[e].Len + len, 2);
if (s == e)
return res;
res += Game(s, e - 1, 0);
for (int i = s; i < e; i++)
{
if (seg[i].Color != seg[e].Color)
continue;
int temp = Game(i + 1, e - 1, 0);
temp += Game(s, i, seg[e].Len + len);
res = max(res, temp);
}
}
int main()
{
memset(Score, -1, sizeof(Score));
int lastc = -1;
int c, index = -1;
for (int i = 0; i < n; i++)
{
cin >> c;
if (lastc != c)
{
index++;
seg[index].Color = c;
seg[index].Len = 1;
lastc = c;
}
else
seg[index].Len++;
}
cout << Game(0, index, 0);
}
深度优先搜索
例题1->寻找路径(待改)
#include <iostream>
using namespace std;
struct Graph
{
int D[20];
int M[20][20];
int Vnum, Enum;
};
bool CheckRepeat(int Arr[], int e, int temp)//检查是否有重复的值
{
for (int i = 0; i < e; i++)
{
if (Arr[i] == temp)
return 1;
}
return 0;
}
Graph CreateG()//生成无向图
{
Graph g;
memset(g.M, 0, sizeof(g.M));
cout << "input Vnum and Enum:";
cin >> g.Vnum >> g.Enum;
int temp;
for (int i = 0; i < g.Vnum; i++)
{
cout << "input data:";
cin >> temp;
while (cin.fail() || CheckRepeat(g.D, i, temp))//检查是否有输入错误或者重复输入
{
cout << "invalid input, input again:";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin >> temp;
}
g.D[i] = temp;
}
int s, e, w;
for (int i = 0; i < g.Enum; i++)
{
cout << "input start and end(index):";
cin >> s >> e;
cout << "input weight:";
cin >> w;
g.M[s][e] = g.M[e][s] = w;
}
return g;
}
bool DFS(Graph g, int s, int e, int *visit)
{
if (s == e)//若起点与终点相同,说明已经到达终点
{
return 1;
}
if (visit[s])//若此点已经被遍历过,直接返回
return 0;
visit[s] = 1;//若没有被遍历过,标记为1
for (int i = 0; i < g.Vnum; i++)//检查与此点相邻的点继续遍历
{
if (g.M[s][i])
{
if (DFS(g, i, e, visit))
{
cout << i << " ";//输出轨迹
return 1;//一旦到达终点,就逐层返回1
}
else
continue;//若遍历后没到达终点,继续进行
}
}
return 0;
}
void Search(Graph g)
{
int s,e,visit[20];
cout << "input start point and end point:";
cin >> s >> e;//输入起点下标
memset(visit, 0, sizeof(visit));//将状态矩阵置0
if (DFS(g, s, e, visit))
cout << endl;
else
cout << "no such way" << endl;
}
int main()
{
Graph g = CreateG();
Search(g);
}
例题2->深度优先遍历
#include <iostream>
using namespace std;
struct Graph
{
int D[20];
int M[20][20];
int Vnum, Enum;
};
bool CheckRepeat(int Arr[], int e, int temp)//检查是否有重复的值
{
for (int i = 0; i < e; i++)
{
if (Arr[i] == temp)
return 1;
}
return 0;
}
Graph CreateG()//生成无向图
{
Graph g;
memset(g.M, 0, sizeof(g.M));
cout << "input Vnum and Enum:";
cin >> g.Vnum >> g.Enum;
int temp;
for (int i = 0; i < g.Vnum; i++)
{
cout << "input data:";
cin >> temp;
while (cin.fail() || CheckRepeat(g.D, i, temp))//检查是否有输入错误或者重复输入
{
cout << "invalid input, input again:";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cin >> temp;
}
g.D[i] = temp;
}
int s, e, w;
for (int i = 0; i < g.Enum; i++)
{
cout << "input start and end(index):";
cin >> s >> e;
cout << "input weight:";
cin >> w;
g.M[s][e] = g.M[e][s] = w;
}
return g;
}
void DFS(Graph g, int s, int *visit)
{
if (visit[s])//若此点已经被遍历过,直接返回
return;
visit[s] = 1;//若没有被遍历过,标记为1并输出
cout << g.D[s] << " ";
for (int i = 0; i < g.Vnum; i++)//检查与此点相邻的点继续遍历
{
if (g.M[s][i] && !visit[i])
DFS(g, i, visit);
}
}
void Start(Graph g)
{
int s,visit[20];
cout << "input start point:";
cin >> s;//输入起点下标
memset(visit, 0, sizeof(visit));//将状态矩阵置0
DFS(g, s, visit);
for (int i = 0; i < g.Vnum; i++)//防止图不连通,那么需要看看还有没有其他连通分支
DFS(g, i, visit);
}
int main()
{
Graph g = CreateG();
Start(g);
}
例题3->城堡问题
#include <iostream>
#include<bitset>
using namespace std;
const int N = 10;
int room[N][N];//储存各个房间的靠墙情况
int color[N][N];//标记room[i][j]是否已经走过
int DFSRoom(int i, int j, int& area)
{
if (color[i][j])//若此房间已经走过,返回
return 0;
area++;//否则发现新房间,面积+1
color[i][j] = 1;//标记
int temp = room[i][j];
room[i][j] &= 1;//通过按位运算来判断此房间有哪些门
if ((room[i][j] == 0) && j - 1 >= 0)
DFSRoom(i, j - 1, area);
room[i][j] = temp;
room[i][j] &= 2;
if ((room[i][j] == 0) && i - 1 >= 0)
DFSRoom(i - 1, j, area);
room[i][j] = temp;
room[i][j] &= 4;
if ((room[i][j] == 0) && j + 1 < N)
DFSRoom(i, j + 1, area);
room[i][j] = temp;
room[i][j] &= 8;
if ((room[i][j] == 0) && i + 1 < N)
DFSRoom(i + 1, j, area);
return area;
}
void Ready()
{
int num = 0, max = 0;
memset(color, 0, sizeof(color));
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
cin >> room[i][j];
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (!color[i][j])//发现新房间
{
num++;//房间数量+1
int temp = 0;
int& area = temp;
max = (max, DFSRoom(i, j, area));
}
}
}
cout << "number of room:" << num << " and the biggest area of room is " << max << endl;
}
int main()
{
Ready();
}
例题4->踩方格
#include <iostream>
using namespace std;
const int N = 5;
int map[N][N];
int visit[N][N];
int Ways(int x, int y, int n)
{
if (n == 0)//n=0说明已经用完步数
return 1;
int num = 0;
visit[x][y] = 1;
if (!visit[x - 1][y] && x - 1 >= 0)//向北走
num += Ways(x - 1, y, n - 1);
if (!visit[x][y - 1] && y - 1 >= 0)//向西走
num += Ways(x, y - 1, n - 1);
if (!visit[x][y + 1] && x + 1 < N)//向东走
num += Ways(x, y + 1, n - 1);
visit[x][y] = 0;//此种情况结束后,把其标志重新置为0,防止干扰其他情况(非常关键的一步)
return num;
}
int main()
{
for(int i=0; i < N; i++)
for(int j=0; j < N; j++)
map[i][j] = 1;
int visit[5][5];
memset(visit, 0, sizeof(visit));
int x, y, n;
cout << "input x,y and n:";
cin >> x >> y >> n;
while(x >= N || y >= N || x < 0 || y < 0 || n > N * N)//防止非法输入
{
cout << "input invalid input, input x,y and n again:";
cin >> x >> y >> n;
}
cout << "total " << Ways(x, y, n) << " ways" << endl;
}
例题5->寻路问题(剪枝思想)
#include <iostream>
#include<vector>
#include<limits>
using namespace std;
struct Road
{
int Des, L, C;
};
vector<vector<Road>>road(100);//邻接表标识图的一种写法(很好用)
int totalfee, totalcity, totalroad;//解决问题需要的用户输入的最基础三个量
int totalcost = 0, minlen = numeric_limits<int>::max(), totallen = 0;//在递归中需要用到的三个量
int visit[100], minroad[100][100];//一个是查看是否访问过的标志矩阵,一个是储存着走到i城市且花了j钱所能走的最优路径
void Walk(int S)
{
if (S == totalcity)//此时说明已经走到终点
{
minlen = min(minlen, totallen);//判断是否需要更新最优路径
return;
}
for (int i = 0; i < road[i].size(); i++)//循环遍历与此起点相连的每个终点
{
Road r = road[S][i];//以S为起点i为终点的路
if (totalcost + r.C > totalfee)//若走这条路花的钱超出预算则放弃这条路
continue;
if (!visit[r.Des])//若这条路在这种情况下还没有被走过
{
if (totallen + r.L >= minlen)//若走这条路后的总路径已经大于当前求得的最优路径,则放弃这条路(剪枝)
continue;
if (r.L + totallen >= minroad[r.Des][totalcost + r.C])//若选择这条路:走到e.Des这座城市且花了totalcos+r.C的钱的总路径已经大于有记载的此种情况下的总路径,那么放弃(剪枝)
continue;
minroad[r.Des][totalcost + r.C];//若上述if不符合,那么更新上述情况下的最优路径
totallen += r.L;//更新路径
totalcost += r.C;//更新花费
visit[r.Des] = 1;//更新标识
Walk(r.Des);//递归
visit[r.Des] = 0;//为了不影响后续的遍历,将已经改变的量重新变为上一步的值
totallen -= r.L;
totalcost-=r.C;
}
}
}
void Ready()
{
cout << "input totalcity, totalroad and totalfee:";
cin >> totalcity >> totalroad >> totalfee;
memset(visit, 0, sizeof(visit));
for (int i = 0; i < totalroad; i++)
{
Road r;
int s;
cout << "input s,Des,L and C:";
cin >> s >> r.Des >> r.L >> r.C;
if (r.Des != i)//防止有路径的期待和终点相同
{
road[s].push_back(r);
}
}
visit[0] = 1;
Walk(0);
if (minlen < numeric_limits<int>::max())//如果最终的minroad小于最开始预设的最大值,那么说明找到了最短路径
cout << minlen << endl;
else
cout << "no such way" << endl;
}
int main()
{
Ready();
}
例题6->生日蛋糕(剪枝思想)
#include <iostream>
#include<limits>
using namespace std;
int minarea = numeric_limits<int>::max(), area = 0;
int Floor, V, R, H;
int best[21][301];
void Cake(int floor, int v, int r, int h)
{
if (floor == 0)//层数为0,已经放置蛋糕完毕
{
if (v)//若体积还不满足,返回重新查找
return;
else//体积也满足,看看是否需要更新最优值
minarea = min(area, minarea);
}
if (v <= 0)//若体积小于0,返回重新查找
return;
for (int i = r; i >= floor; i--)//循环取合适的半径值
{
if (Floor == floor)//若这俩相等,说明现在是整个蛋糕的最底层,那么整个圆面积就是最大面积的平方
area = pow(i, 2);
for (int j = h; j >= floor; j--)//循环取合适的高值
{
if (v - pow(i, 2) * j < 0)//(剪枝)若取此种情况后体积超出下限,放弃这种情况
continue;
area += 2 * i * j;//面积更新
if (area > best[floor][v - i * i * j])//(剪枝)若取此种情况,得到的结果超过此种情况之前所记录过的最优解,放弃
continue;
else
best[floor][v - i * i * j] = area;//若是此种情况的最优解,则更新
Cake(floor - 1, v - pow(i, 2) * j, i - 1, j - 1);//递归继续查找
area -= 2 * i * j;//将改变过的值改回,防止影响其他情况下的判断
}
}
}
int main()
{
for (int i = 0; i <= 20; i++)
for (int j = 0; j <= 300; j++)
best[i][j] = 1e4;
cout << "input Floor and V:";
cin >> Floor >> V;
Cake(Floor, V, 5, 5);
if (minarea < numeric_limits<int>::max())
cout << "minimum area is " << minarea << endl;
else
cout << "no suitable way to cut" << endl;
}
广度优先搜索
贪心算法
例题1->圣诞老人的礼物
#include <iostream>
#include<algorithm>
#define EPS 1e-6
using namespace std;
struct Gift
{
int V;
int W;
bool operator <(const Gift& c)
{
return double(V / W) > double(c.V / c.W) > EPS;// 重载>运算符
}
}gift[100];
void Pick()
{
int n, weight = 0;
cout << "input how many gifts and total weight:";
cin >> n >> weight;
for (int i = 0; i < n; i++)
{
cout << "input the value and weight of the gift:";
cin >> gift[i].V >> gift[i].W;
}
sort(gift, gift + n);//依据价值/质量(比值)来进行排序
double totalw = 0, totalv = 0;
for (int i = 0; i < n; i++)
{
if (totalw += gift[i].W <= weight)//还能放得下这个礼物
{
totalw += gift[i].W;
totalv += gift[i].V;
}
else//放不下整个这个礼物了,那么放一部分进去
{
totalv += gift[i].V / gift[i].W * (weight - totalw);
break;//可以结束放礼物了
}
}
cout << "max value is " << totalv << endl;
}
int main()
{
Pick();
}
例题2->电影节
#include <iostream>
#include<algorithm>
using namespace std;
struct Film
{
int S;
int E ;
bool operator <(const Film& f)
{
return E < f.E;// 重载<运算符
}
}film[100];
void Watch()
{
int n, flag = 0;
cout << "input how many movies:";
cin >> n;
for (int i = 0; i < n; i++)
{
cout << "input the start time and end time of the movie:";
cin >> film[i].S >> film[i].E;
}
sort(film, film + n);//依据电影结束时间来进行排序
int totalm = 1;//预设为1,至少看一场电影
for (int i = 1; i < n; i++)//第一场电影肯定会看,所以从第二场电影开始计数
{
if (film[i].S >= film[flag].E && film[i].E < 24)//下一场的开始时间在这一场的结束时间之后且不超过晚上24点
{
totalm++;
flag = i;
}
}
cout << "max value is " << totalm << endl;
}
int main()
{
Watch();
}