一、最大公约数和最小公倍数
最大公约数,是用递归来求,最小公倍数是两个数相乘并在除以最大公约数
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int gcd (int a, int b)
{
if (b == 0) return a;
else
{
gcd (b, a % b);
}
}
int main ()
{
int a = 0, b = 0, c = 0;
cin >> a >> b;
c = gcd(a,b); //最大公约数
int d = 0;
d = (a * b) / c;//最小公倍数
cout << c << " " << d << endl;
return 0;
}
//如果要是三个三个的找最小公倍数,那么就两个两个找,先找第一个和第二个,在把第一个和第二个的最小公倍数和最后一个数找最小公倍数。
二、日期和时间的处理
关于时间的处理
小时 = x / 3600;
分钟 = x % 3600 / 60;
秒 = x % 60;
//其他的类似
闰年:
year可以整除4但不可以整除100,或者可以整除400
三、进制的转化
在进制转换的时候,要知道一件事情,关于10-15用A-F表示的时候,要知道10,11,12 ~ 15,是单独的数据,出现类似FF的时候时,应该把他挨个计算,不能当作1515 % 10来计算,只能,把15单独列出来,让15 * n^x,来计算。
//p进制转化为10进制的方法
//p是代表进制的数字表述
int y = 0, product = 1;
while (x != 0)
{
y = y + (x % 10) * product;
x = x / 10;
product = product * P;
}
//x % 10 表示每次获得,x的最后一位(个位),x / 10,表示把最后一位去掉,让十位变成个位。
//10进制变成 Q进制(除基取余法,正着输入,倒着输出)
int z[40], num = 0;
do
{
z[num++] = y % Q;
y = y / Q;
}while (y != 0);
设计10进制到16进制转化的经典题目
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <string>
using namespace std;
int ito(char a) //字母转数字(主要是针对10进制以上的)
{
if (a == 'A') return 10;
if (a == 'B') return 11;
if (a == 'C') return 12;
if (a == 'D') return 13;
if (a == 'E') return 14;
if (a == 'F') return 15;
return (a - '0');
}
char oti(int a)
{
if (a == 10) return 'A';
if (a == 11) return 'B';
if (a == 12) return 'C';
if (a == 13) return 'D';
if (a == 14) return 'E';
if (a == 15) return 'F';
return char(a + '0');
}
int main()
{
int n, m,temp = 0;
string s,res = "";
cin >> n;
getchar();
cin >> s;
cin >> m;
for (int i = 0; i < s.size(); i++)
{
temp = temp + ito(s[i]) * pow(n, s.size() - i - 1);
}
int z[40] = { 0 }, count = 0;
do
{
res = oti(temp % m) + res;
temp /= m;
} while (temp != 0);
cout << res;
return 0;
}
关于10进制转换成比10进制小的在int范围内不考虑范围的容器(10进制转8进制来说)
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <string>
#include <stack>
using namespace std;
stack <int> q;
int n;
int main()
{
cin >> n;
cout << 0;
while (n)
{
if (n < 8)
{
q.push(n);
break;
}
else {
q.push(n % 8);
n /= 8;
}
}
while (!q.empty())
{
cout << q.top();
q.pop();
}
return 0;
}
同进制的加法(用到高精度加法概念)
#include <iostream>
#include <cstdio>
#include <map>
#include <string>
#include <queue>
#include <cstring>
#include <algorithm>
#include<cmath>
using namespace std;
int n = 0;
vector<int> add(vector<int>& a, vector<int>& b)
{
if (a.size() < b.size()) return add(b, a);
vector<int> c;
int t = 0;
for (int i = 0; i < a.size(); i++)
{
t += a[i];
if (i < b.size()) t += b[i];
c.push_back(t % n);
t /= n;
}
if (t) c.push_back(t);
return c;
}
int main()
{
vector<int> A, B;
string a, b;
cin >> n;
getchar();
cin >> a;
for (int i = a.size() - 1; i >= 0; i--) {
if (a[i] >= '0' && a[i] <= '9')
{
A.push_back(a[i] - '0');
}
else if(a[i] >= 'A' && a[i] <= 'Z') {
A.push_back(a[i] - 'A' + 10);
}
}
getchar();
cin >> b;
for (int i = b.size() - 1; i >= 0; i--) {
if (b[i] >= '0' && b[i] <= '9')
{
B.push_back(b[i] - '0');
}
else if (b[i] >= 'A' && b[i] <= 'Z') {
B.push_back(b[i] - 'A' + 10);
}
}
auto c = add(A, B);
for (int i = c.size() - 1; i >= 0; i--)
{
if (c[i] >= 10) {
cout << char(c[i] + 'A' - 10);
}
else cout << c[i];
}
return 0;
}
十六进制转换成二级制,二级制转换成十六机制
十六进制转成2进制,二进制转成8进制
这样进制转换的方法
十六进制转二进制,四位一体法
A6 - > 二进制
(A = 10 = 8 + 2, 6 = 4 + 2)
(8 4 2 1 8 4 2 1) ->
(1 0 1 0 0 1 1 0)
故A6的二进制为1010 0110
1010 0110 -> 八进制,(三位为一体,不过补三位,缺几个0,补几个0,往最开头补0,三位一体法)
0 1 0 1 0 0 1 1 0(这样分),在利用421,来计算八进制
0*4 + 1 * 2 + 0*1 = 2
1 * 4 + 0*2 + 0*1 = 4
1 * 4 + 1*2 + 0*1 = 6
所以八进制为246
具体实例
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
string s;
int n = 0;
cin >> n;
getchar();
for (int i = 0; i < n; i++)
{
getline(cin, s);
string t = "";
for (int j = 0; j < s.size(); j++)
{
switch (s[j])
{
case '0': t += "0000"; break;
case '1': t += "0001"; break;
case '2':t += "0010"; break;
case'3':t += "0011"; break;
case '4':t += "0100"; break;
case '5':t += "0101"; break;
case'6':t += "0110"; break;
case'7':t += "0111"; break;
case '8':t += "1000"; break;
case '9':t += "1001"; break;
case 'A':t += "1010"; break;
case 'B':t += "1011"; break;
case 'C':t += "1100"; break;
case 'D':t += "1101"; break;
case 'E':t += "1110"; break;
case 'F':t += "1111"; break;
}
}
int len = t.size();
//三位一体补0
if (len % 3 == 1) {
t = "00" + t;
}
else if (len % 3 == 2) {
t = "0" + t;
}
int flag = 0; //排除先导0
for (int k = 2; k < t.size(); k += 3)
{
int sum = 0; //八进制的数值
sum = (t[k - 2] - '0') * 4 + (t[k - 1] - '0') * 2 + (t[k] - '0') * 1;
if (sum != 0) flag = 1;
if (flag == 1) {
cout << sum;
}
}
cout << endl;
}
return 0;
}
四、素数(又称质数)
bool isprime(int a)
{
int b = sqrt(a);
if (a <= 1) return false;
for (int i = 2; i <= b; i++)
{
if (a % i == 0) return false;
}
return true;
}
五、质因子的分解
//首先的是个素数,才是质因子
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 100010;
bool isprime(int a)
{
int b = sqrt(a);
if (b <= 1) return false;
for (int i = 2; i <= b;i++)
{
if (a % i == 0)
{
return false;
}
}
return true;
}
//素数表
int prime[maxn] = {0}, pnum = 0; //存素数的表,个个数
void Find_prime() //求素数表
{
for (int i = 1; i < maxn; i++)
{
if (isprime(i) == true)
{
prime[pnum++] = i; //从而有了素数表
}
}
}
struct factor
{
int x ;//x为质因子
int cnt;//cnt为质因子个数
} fac[10];
int main ()
{
Find_prime();
int n = 0; //n为要分解的数,把它分解为若干质因子
int num = 0; //num为不同的质因子的个数
cin >> n;//不过需要进行特判,1的质因子是1
if (n == 1) cout << "1 = 1" << endl;
else
{
printf("%d = ",n);
int sqr = (int)sqrt(n * 1.0); //对该数进行一半的划分
//枚举根号以内的质因子
for (int i = 0; i < pnum && prime[i] <= sqr; i++)
{
if (n % prime[i] == 0)
{
fac[num].x = prime[i]; //记录该因子
fac[num].cnt = 0;
while (n % prime[i] == 0)
{
fac[num].cnt ++;
n /= prime[i];
}
num++; //不同质因子个数加一
}
if (n == 1) break; //及时推出循环,节省时间
}
if (n != 1) //无法被根号n以内的质因子除尽
{
fac[num].x = n;
fac[num++].cnt = 1;
}
//按照格式输出
for (int i = 0; i < num; i++)
{
if (i > 0) printf("*");
printf("%d",fac[i].x );
if (fac[i].cnt > 1)
{
printf("^%d",fac[i].cnt );
}
}
}
return 0;
}
求某个阶乘的质因子分解(故名思意:将一个正整数n写成一个或多个质数乘积的形式)
我的错误点在于循环出,while(),而我却经常用if()。
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <stack>
using namespace std;
int bus[100010];
bool isprime(int a)
{
if (a <= 1) return false;
int q = sqrt(a);
for (int i = 2; i <= q; i++)
{
if (a % i == 0) return false;
}
return true;
}
//各个质因子出现的次方之和为阶乘之和
int main()
{
int n = 0;
cin >> n;
for (int i = 2; i <= i; i++) //判断阶乘的每位数字的质因子,就是该阶乘的质因子
{
int j = i; //j存变量i,目的是,利用j去看i的质因子是谁(i是从2到n)
for (int k = 1; k <= n; k++)
{
while ((j % k == 0) && isprime(k) && j > 1) //首先k为j的因子,k必须是质数,某数小于等于1,会让其破化质数性质
{
bus[k]++;//存储该质数的因子出现了几次
j /= k;//目的是能让循环出去,并且判断改整数j在k情况下,有几个质数k.
}
}
}
for (int i = 0; i <= n; i++)
{
if (bus[i]) cout << i << " " << bus[i] << endl;
}
return 0;
}
不用设数组方法:边用边输出,不会有超时问题
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <stack>
using namespace std;
typedef long long ll;
int main()
{
ll n = 0;
scanf_s("%lld", &n);
if (n == 1) { cout << "1=1"; return 0; }
printf("%lld=", n);
int flag = 0;
for (int i = 2; i <= n / i; i++)
{
int count = 0;
while (n % i == 0)
{
n /= i;
count++;
}
if (count > 0)
{
if (flag == 0)
{
flag = 1;
cout << i;
}
else {
cout << "*" << i;
}
if (count > 1) cout << "^" << count;
}
}
if (n > 1)
{
if (flag == 1) printf("*%lld", n);
else printf("%lld", n);
}
return 0;
}
六、分数的表示与化简
如果没有那么复杂,就是让求分数的话,可以这样求
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
long long gcd(long long a, long long b) //最大公约数
{
a = abs(a);
b = abs(b);
if(b == 0) return a;
else{
return gcd(b, a % b);
}
}
int main()
{
int T = 0;
cin >> T;
for (int i = 0; i < T; i++)
{
int a = 0, b = 0, n = 0;
cin >> a >> b >> n;
long double maxn = -1000000;
long long down = 0, up = 0;
for (int j = 0; j <= n; j++)
{
double f = (a * j + b) * (1.0) / pow(2,j);
if(f > maxn)
{
maxn = f;
down = pow(2,j);
up = (a * j + b);
}
}
long long temp = gcd(up, down);
down /= temp;
up /= temp;
if(down == 1) cout << up << endl; //分子等于1,输出分母
else {
cout << up << "/" << down << endl;
}
}
return 0;
}
强调一点,由于分数的乘法除法可能使分子或分母超过int型表示的范围,因此一般情况下,分子分母应当使用long long型来储存。(建议全部改成long long 型数据,要不然会过不了全部测试点)
分数的输出:
1、输出分数前要对其进行化简
2、如果分母为1,则直接输出分子
3、如果分子绝对值大于分母绝对值,假分数。整数部分为r.pu/r.down, 分子部分为abs(r.up) % r.down, 分母部分为r.down
4、以上均不满足是,说明分数r,是真分数,按原样输出即可。
化简的三项规定
1、分母位负数
2、分子up为0,分母down为1
3、约分:求出分子分母绝对值最大公因数d,后令分子分母都除以d;
//分数的表示与化简
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
struct Fraction
{
long long up; //分子
long long down; //分母
};
long long gcd (long long a, long long b) //最大公因数(约数)
{
if (b == 0) return a;
else
{
return gcd (b, a % b);
}
}
Fraction reduction(Fraction result) //分数的化简
{
if (result.down < 0) //分母小于0,就让分子分母都变成相反数
{
result.down = - result.down ;
result.up = - result.up ;
}
if (result.up == 0) //如果分子是0,则必须让分母等于1
{
result.down = 1;
} else { //分子不是0,进行约分
int d = gcd(abs(result.up ),abs(result.down )); //分子分母的最大工约数
result.down /= d;
result.up /= d;
}
return result;
}
//分数的四则运算
Fraction add (Fraction f1, Fraction f2) //分数的和
{
Fraction result;
result.up = f1.up * f2.down + f2.up * f1.down ;
result.down = f1.down * f2.down ;
return reduction(result); //化简后的值
}
Fraction sub (Fraction f1, Fraction f2) //分数的减
{
Fraction result;
result.up = f1.up * f2.down - f2.up * f1.down ;
result.down = f1.down * f2.down ;
return reduction(result);
}
Fraction mul (Fraction f1, Fraction f2) //分数的乘法
{
Fraction result;
result.down = f1.down * f2.down ;
result.up = f1.up * f2.up ;
return reduction(result);
}
Fraction div (Fraction f1, Fraction f2) //分数的除法
{
Fraction result;
result.up = f1.up * f2.down ;
result.down = f1.down * f2.up ;
return reduction(result);
}
void showResult (Fraction r) //输出分数r
{
r = reduction (r); //1、对分数进行化简
if (r.down == 1) printf("%lld",r.up ); //2、分母为1,直接输出分子
else if (abs(r.up) > r.down ) { //假分数
printf("%lld %lld/%lld",r.up/r.down , abs(r.up) % r.down ,r.down );
} else { //真分数
printf("%lld/%lld",r.up ,r.down );
}
}
int main ()
{
Fraction f1, f2;
scanf("%lld/%lld %lld/%lld",&f1.up ,&f1.down ,&f2.up ,&f2.down );
showResult(f1);
cout << " + ";
showResult(f2);
cout << " = ";
showResult(add(f1,f2));
cout << endl;
showResult(f1);
cout << " - ";
showResult(f2);
cout << " = ";
showResult(sub(f1,f2));
cout << endl;
showResult(f1);
cout << " * ";
showResult(f2);
cout << " = ";
showResult(mul(f1,f2));
cout << endl;
showResult(f1);
cout << " / ";
showResult(f2);
cout << " = ";
if(f2.up != 0)
{
showResult(div(f1,f2));
} else {
printf("Inf");
}
cout << endl;
return 0;
}
七、全排列
//递归法()
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
int p[100]; //存放 当前排列
int n = 0;
int hashtable[100] = {false}; //判段某数字在当前位是否出现过
void dfs(int index) //index 处理当前排列
{
if(index == n + 1) //递归边界,且还要知道做什么
{
for(int i = 1; i <= n; i++) //找到递归边界后,知道了存放排列值满员了,输出即可
{
if(i == 1) cout << p[i];
else cout << " " << p[i];
}
cout << endl;
return ;//开始往回返
}
for(int i = 1; i <= n; i++) //寻找1 ~ n开头的排列式子
{
if(hashtable[i] == false) //表明该数字还没存入p中
{
hashtable[i] = true;
p[index] = i;
dfs(index + 1); //处理index + 1 号排列
hashtable[i] = false; //处理完p[index]位x的子问题,还原状态。
}
}
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
//函数法
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
int a[100];
int main()
{
int n = 0;
cin >> n;
for(int i = 0; i < n; i++)
{
a[i] = i + 1;
}
do
{
for(int i = 0; i < n; i++)
{
cout << a[i] << " ";
}
cout << endl;
}while(next_permutation(a, a + n));
return 0;
}
八、排序
1、冒泡排序
/*冒泡排序法:
首先要理解需要进行几趟比较,每趟比较中需要比较多少次
冒泡排序法是(以从小到大排序为例)在第一趟中将第一个大的数与下面的数依次比较知到将最大的数沉入底部其他小的数得到上升,
因为最大的沉入到了底部,所以在趟数减一的同时,每趟的比较次数也减一
第二趟第三趟……也是如此方法,直到全部按从小到大排完为止
例如,有n个数,需要比较n-1趟,每一趟比较n-1-j趟(j表示这为这是第几趟的序号)过了一趟就少比较一次
且在调换的时候是用每一趟中比较的趟数调换的*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int n = 0, ans = 0;
int a[10010] = {
0 };
void sort1(int a[])
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1]) {
swap(a[j], a[j + 1]); }
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort1(a);
for (int i = 0; i < n; i++)
{
if (i == 0) cout << a[i];
else cout << " " << a[i];
}
return 0;
}
2、选则排序法
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int n = 0, ans = 0;
int a[10010] = {
0 };
void sort1(int a[])
{
for (int i = 0; i < n - 1; i++)
{
int temp = i;
for (int j = i + 1; j < n; j++)
{
if (a[temp] > a[j])
{
swap(a[temp], a[j]);
ans++;
}
}
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort1(a);
for (int i = 0; i < n; i++)
{
if (i == 0) cout << a[i];
else cout << " " << a[i];
}
return 0;
}
3、快速排序
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int n = 0, ans = 0;
int a[100010] = {
0 };
void sort1(int a[],int left, int right)
{
if (left >= right) return;
int i = left - 1, j = right + 1, mid = a[(left + right) / 2];
while (i < j)
{
do i++; while (a[i] < mid);
do j--; while (a[j] > mid);
if (i < j)
{
swap(a[i], a[j]);
}
}
sort1(a, left, i - 1);
sort1(a, j + 1, right);
}
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
sort1(a,0,n -1);
for (int i = 0; i < n; i++)
{
if (i == 0) cout << a[i];
else cout << " " << a[i];
}
return 0;
}
4、归并排序
#include <iostream>
using namespace std;
const int maxn = 100;
int a[maxn];
//对数组A的[L1,R1],[L2, R2]区间合并为有序区间
void merge(int a[], int L1, int R1, int L2, int R2)
{
int i = L1, j = L2;
int temp[maxn], index = 0;//temp为临时存放合并的数组,index为其下标
while (i <= R1 && j <= R2)
{
if (a[i] <= a[j])
{
temp[index++] = a[i++];
}
else
{
temp[index++] = a[j++];
}
}
while (i <= R1)//将[L1, R1]剩余的元素加入序列temp中
temp[index++] = a[i++];
while (j <= R2)//将[L2,R2]剩余的元素加入序列temp中
temp[index++] = a[j++];
for (int i = 0; i < index; i++)
{
a[L1 + i] = temp[i];将合并后的序列赋值回数组A,
}
}
void mergeSort(int a[], int left, int right)
{
if (left < right) //归并排序
{
int mid = (left + right) / 2;//取[left,right]的中间值
mergeSort(a, left, mid); //递归,将左子区间归并排序
mergeSort(a, mid + 1, right); //递归,右子区间归并排序
merge(a, left, mid, mid + 1, right);//将左子区间和右子区间和并
}
}
int main()
{
int n = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> a[i];
}
mergeSort(a, 0, n - 1);
for (int i = 0; i < n; i++)
{
if (i != n - 1)
{
cout << a[i] << " ";
}
else
{
cout << a[i];
}
}
return 0;
}
5、堆排序
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int n, m;
int heap[100010];
void downadjust(int low, int high) //如果是小顶堆,改了一个数,改数比较大,往下移,up同样的道理
{
int i = low, j = i * 2;
while (j <= high)
{
if (j + 1 <= high && heap[j + 1] < heap[j])//小顶堆和大顶堆体现在这里找最小的
{
j++;
}
if (heap[j] < heap[i])//与头节点比较
{
swap(heap[i], heap[j]);
i = j; //该数据还需要调整
j = i * 2;
}
else {
//退出就好,表示调好了
break;
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> heap[i];
}
//建堆
for (int i = n / 2; i; i--)
{
downadjust(i, n);
}
while (m--)
{
cout << heap[1] << " ";
heap[1] = heap[n--];
downadjust(1, n);
}
return 0;
}
6、插入排序
int A[maxn],n; //n为元素个数,数组下标为1~n
void insertsort()
{
for (int i = 2; i <= n; i++) //进行n-1趟排序
{
int temp = A[i],j = i; //temp临时存放A[i],j从i开始往前枚举
while(j > 1 && temp < A[j - 1])//只要temp小于前一个元素A[j - 1]
{
A[j] = A[j - 1];//把A[j - 1] 后移动一位至A[j - 1]
j--;
}
A[j] = temp;//插入位置为j
}
}
7、桶排序
// 桶排序法:设定一个数组,该数组能装下你输入所有的数据,所以,你输入的数据,是被当做下标处理的
//首先定义你一方位足够大的桶,就是数组
//然后输入数据,让其当作下标并把a[下标]的值加一,在用if语句,加上continue来排除相同的下标,这样,每一份a[下标]的值,都是1,
//再用sum统计每一份a[下标]的个数,就是sum++
//然后用for循环,把下标的范围当成条件,进行输出下标以此方法得到了查重并将其不同的下标值输出
//输出的下标是从小到大,或从到大小的,就完成了排序的功能
#include <stdio.h>
int main()
{
int a[1001]={
0},N,i,x,sum=0;
scanf("%d",&N);
for (i=0;i<N;i++){
scanf("%d",&x);
if(a[x]){
continue;//如果a[i]这个已经加一变成了一,就表示下标的那个值已经存在了,
//然后就不对此a[x]赋第二次值,让其变成2,3,或者更多,以达到去重效果
}
a[x]++;
sum++;//总数量加一
}
printf("%d\n",sum);
for(i=0;i<1000;i++){
if(a[i]){
//如果a[i]的值已经得到加一,就可以把下标的值输出
printf("%d ",i);
}
}
printf("\n");
return 0;
}
8、cmp排序,重名次情况
成绩相同的学生享有并列的排名,排名并列时,按账号的字母序升序输出问题在于享有并列的排名
bool cmp(node a, node b)
{
if(a.score != b.score)
{
return a.score > b.score;
} else {
return a.name < b.name;
}
}//这是cmp的排序
当输入好后,对数组sort,后,可以依次按要求输出名词和分数,但是会有享有相同名次的情况,解决方式
设定一个数组,b[n],该值是从0 ~ n - 1的,完全可以表示名次,但是有同名次,解决方式为:
b[0] = 1;
for(int i = 1; i < n; i++)
{
if(N[i].score == N[i - 1].score )
{
b[i] = b[ i - 1];
}
else {
b[i] = i + 1;
}
}
九、高精度四则运算
//高精度加法字符串类型 + 判断是否为回文数
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
string add(string a, string b) //字符串形式加和
{
string c;
int i = a.size() - 1;
int bas = 0, adv = 0; //当前值,进位值
while (i >= 0 )
{
bas = (a[i] - '0') + (b[i] - '0'); //当前位所得值
c += (adv + bas) % 10 + '0'; //当前位最终值
adv = (adv + bas) / 10; //进位值
--i;
}
if (adv) c += (adv + '0') ;//若进位值还有值,则做最后的加和
reverse(c.begin(),c.end()) ;
return c;
}
bool ispalindromic(string c)
{
int len = c.size() ;
bool flag = true;
for (int i = 0; i < len / 2; i++)
{
if (c[i] != c[len - 1 - i]) flag = false;
}
return flag;
}
int main ()
{
string A, B,C;
cin >> A;
if (ispalindromic(A))
{
cout << A << " is a palindromic number." << endl; //开始即为回文数
return 0;
}
int cnt = 10;
bool flag = false;
while (cnt--) //仅限十步
{
B = A;
reverse(B.begin(),B.end()) ;
C = add(A, B);
cout << A << " + " << B << " = " << C << endl;
if (ispalindromic(C)) //如果c是回文数,则继续操作
{
cout << C << " is a palindromic number." << endl;
flag = true;
return 0;
}
A = C;
}
if (flag == false) //十步之内未找到回文数
{
cout << "Not found in 10 iterations." << endl;
}
return 0;
}
#include <string>
#include <iostream>
#include <vector>
using namespace std;
vector<int> add(vector<int> &A, vector<int>&B) //高精度加法
{
if (A.size() < B.size()) return add(B, A); //保证是长的数据加短的数据
vector<int>C;
int t = 0; //进位的做法
for (int i = 0; i < A.size(); i++)
{
t += A[i];
if(i < B.size())
{
t += B[i];
}
C.push_back(t % 10); //取个位,进上去值被加到t里面去了
t /= 10;
}
if (t) C.push_back(t); //如果还有最后一个进上去的位数没有被加上,通过这条语句来加上
return C;
}
int main ()
{
vector<int>A , B;
string a, b;
cin >> a >> b;
for (int i = a.size() - 1; i >= 0; i--)
{
A.push_back(a[i] - '0'); //倒着存放
}
for (int i = b.size() - 1; i >= 0; i--)
{
B.push_back(b[i] - '0'); //倒着存放
}
auto C = add(A, B);
for (int i = C.size() - 1; i >= 0; i--) //倒着输出
{
cout << C[i];
}
return 0;
}
//高精度减法
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector <int> sub(vector<int>&A, vector<int>&B)
{
if (A.size() < B.size()) return sub(B, A);
vector<int> C;
int t = 0; //借位
for (int i = 0; i < A.size(); i++)
{
t = A[i] - t;
if (i < B.size())
{
t -= B[i];
}
C.push_back((t + 10) % 10); //按照借位的方法存入(t负数的话,借一加十,正数的话,取余留个位)
//借位处理
if(t < 0) t = 1; //通过下一次循环,还回去那个1 (t = A[i] - t)
else t = 0;
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //去除002这种情况,只输出2
return C;
}
int main ()
{
string a, b;
cin >> a >> b;
vector<int> A, B;
for (int i = a.size() - 1; i >= 0; i--)
{
A.push_back(a[i] - '0');
}
for (int j = b.size() - 1; j >= 0; j--)
{
B.push_back(b[j] - '0');
}
auto C = sub(A, B);
for (int i = C.size() - 1; i >= 0; i--)
{
cout << C[i];
}
return 0;
}
//高精度乘以低精度
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector <int> mul (vector<int>&A, int b)
{
vector<int>C;
int t = 0;
for (int i = 0; i < A.size() || t; i++) // ||t的原因是最后如果t存有数据,将其全部给掉C,或的原因是防止 0 * b而结束循环;
{
if (i < A.size()) t += A[i] * b; //每个数据都乘以b,
C.push_back(t % 10);
t /= 10; //有进位的情况
}
while (C.size() > 1 && C.back() == 0) C.pop_back(); //解决002这种情况而输出2
return C;
}
int main ()
{
string a;
int b = 0;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i--)
{
A.push_back(a[i] - '0');
}
auto C = mul(A, b);
for (int i = C.size() - 1; i >= 0; i--)
{
cout << C[i];
}
return 0;
}
//高精度除以低精度
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
vector <int> div (vector<int>&A, int b, int &r)
{
vector<int>C;
int t = 0;
r = 0;
for (int i = A.size() - 1; i >= 0; i--)
{
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(),C.end()); //翻转
while (C.size() > 1 && C.back() == 0) C.pop_back(); //解决002这种情况而输出2
return C;
}
int main ()
{
string a;
int b = 0;
int r = 0;
cin >> a >> b;
vector<int> A;
for (int i = a.size() - 1; i >= 0; i--)
{
A.push_back(a[i] - '0');
}
auto C = div(A, b,r);
for (int i = C.size() - 1; i >= 0; i--)
{
cout << C[i];
}
cout << endl << r; //余数
return 0;
}
高精度求阶乘之和
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <string>
using namespace std;
int a[2000];
int b[2000];
int c[2000];
void mul(int* a, int d)
{
int ans = 0;
for (int i = 1; i <= 1000; i++)
{
a[i] = a[i] * d + ans;
ans = a[i] / 10;
a[i] %= 10;
}
}
void add(int* a, int *c)
{
int ans = 0;
for (int i = 1; i <= 1000; i++)
{
c[i] += a[i] + ans;
ans = c[i] / 10;
c[i] %= 10;
}
}
int main()
{
int n = 0;
cin >> n;
a[1] = 1;
for (int i = 1; i <= n; i++)
{
mul(a, i);
add(a, c);
}
int flag = 0;
for (int i = 1000; i >= 1; i--)
{
if (c[i] != 0) flag = 1;
if (flag) cout << c[i];
}
return 0;
}
//高精乘以高精度
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
#include <stack>
using namespace std;
int A[10010], B[10010], c[10010];
char a[10010], b[10010];
int main()
{
int lena, lenb;
cin >> a >> b;
lena = strlen(a);
lenb = strlen(b);
for (int i = 1; i <= lena; i++)
{
A[i] = a[lena - i] - '0';
}
for (int i = 1; i <= lenb; i++)
{
B[i] = b[lenb - i] - '0';
}
for (int i = 1; i <= lena; i++)//计算乘法的时候先不考虑进位,先让i + j - 1; 而i就是我们说的错位相加。
{
for (int j = 1; j <= lenb; j++)
{
c[i + j - 1] += A[i] * B[j];
}
}
for (int i = 1; i < lena + lenb; i++)//无论数字如何大,数位也不会大于两个乘数的和
{
if (c[i] > 9) //大九需要进位
{
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
}
int len = lena + lenb;
while (c[len] == 0 && len > 1) len--;//去除前导0
for (int i = len ; i >= 1; i--)
{
cout << c[i];
}
return 0;
}
十、线性表
1、动态链表
1、创建链表
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <iostream>
#include <stdlib.h>
using namespace std;
struct node{
int data;//数据
node* next;
};
//创建链表
node* create(int a[])
{
node* p, *pre,*head;//pre保存当前结点的前驱结点
head = new node;//创建头节点
head -> next = NULL; //头节点不需要数据
pre = head; //记录当前节点
for(int i = 0; i < 5; i++)
{
p = new node; //开创新节点
p->data = a[i];
p->next = NULL;
pre->next = p;
pre = p; //把pre设为p,作为下节点的前驱结点
}
return head;
}
int main ()
{
int a[5] = {
5,3, 6,1,2};
node* L = create(a);
L = L->next;
while(L != NULL)
{
printf("%d ",L->data );
L = L->next;
}
return 0;
}
2、查找元素
//查找元素x的个数
int search(node* head, int x)
{
int count = 0;
node* p = head->next;
while(p != NULL)
{
if(p->data == x){
count ++;
}
p = p->next;
}
return count;
}
3、插入元素
//将元素x插入到位置pos前处
void insert(node* head, int pos, int x)
{
node* pre = head;
pre = pre->next;
for(int i = 0; i < pos - 1; i++)
{
pre = pre-> next;
}
node* p = new node;
p->data = x;
p->next = pre-> next;
pre->next = p;
}
4、删除元素
//删除元素x
void del(node* head, int x)
{
node*pre = head;
node*p = head->next;
while(p!=NULL)
{
if(p->data == x)
{
pre->next = p->next;
delete(p);
p = p->next;
}
else{
pre = p;
p = p->next;
}
}
}
实例:
已有a、b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号升序排列,输入:第一行,a、b两个链表元素的数量N、M,用空格隔开。 接下来N行是a的数据 然后M行是b的数据 每行数据由学号和成绩两部分组成
输出:按照学号升序排列的数据
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <iostream>
#include <stdlib.h>
using namespace std;
struct node{
int num;
int score;
node* next;
};
void insert(node* head, node* b)
{
node* pre, *p;
pre = head;
p = head->next;
while(p != NULL && p->num < b->num )
{
pre = p;
p = p->next;
}
pre->next = b;
b->next = p;
}
int main ()
{
node* head, *p;
head = new node;
head->next = NULL;
int n, m;
cin >> n >> m;
for(int i = 0; i < n + m; i++)
{
p = new node;
p->next = NULL;
scanf("%d %d",&p->num, &p->score);
insert(head,p);
}
for(p = head->next; p != NULL; p = p->next )
{
printf("%d %d\n",p->num, p->score );
}
return 0;
}
2、静态链表
原理的实现是靠的hash表,不需要头节点
具体模板如下
//建立结构体
struct Node{
int address;//终点地址
typename data;//数据域
int next; //指针域
}node[size];//变量名与结构体名尽量不要一样
//静态链表初始化
for(int i = 0; i < maxn; i++)
{
node[i].xxx = 0;
}
//p=给出的地址,count = 0;
while(p != -1)//-1代表链表结束
{
p = node[p].next;
xxx; //性质
}
具体实例
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
struct node {
int data;
int next;
}list[100010];
vector<int>v[2];
int a[100010] = {
0 };
int main()
{
int first, N = 0;
cin >> first >> N;
int temp = 0;
for (int i = 0; i < N; i++)
{
cin >> temp;
cin >> list[temp].data >> list[temp].next;
//a[list[temp].data]++;
}
int p = first;
while (p != -1) {
int count = list[p].data;
if (a[abs(count)] >= 1) {
v[1].push_back(p);
}
else if (a[abs(count)] == 0) {
v[0].push_back(p);
}
a[abs(count)]++;
p = list[p].next;
}
//cout << "v[0].size() = " << v[0].size() << endl;
//cout << "v[1].size() = " << v[1].size() << endl;
int flag = 0;
for (int i = 0; i < v[0].size(); i++)
{
if (flag == 0) {
printf("%05d %d ", v[0][i],list[v[0][i]].data);
flag = 1;
}
else {
printf("%05d\n%05d %d ", v[0][i], v[0][i], list[v[0][i]].data);
}
}
cout << "-1" << endl;
if (v[1].size() != 0) {
flag = 0;
for (int i = 0; i < v[1].size(); i++)
{
if (flag == 0) {
printf("%05d %d ", v[1][i], list[v[1][i]].data);
flag = 1;
}
else {
printf("%05d\n%05d %d ", v[1][i], v[1][i], list[v[1][i]].data);
}
}
cout << "-1" << endl;
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
struct node {
int pre;
int data;
int next;
}list[100010];
vector<node>v;
int main()
{
int N, first;
cin >> first >> N;
for (int i = 0; i < N; i++)
{
int temp = 0;
cin >> temp;
cin >> list[temp].data >> list[temp].next;
list[temp].pre = temp;
}
while (first != -1) {
v.push_back(list[first]);
first = list[first].next;
}
int l = 0, r = v.size() - 1;
int count = 0;
while (1) {
if (count + 1 == v.size() ){
printf("%05d %d -1", v[r].pre, v[r].data);
break;
}
printf("%05d %d %05d\n", v[r].pre, v[r].data, v[l].pre);
count++;
if (count + 1 == v.size()) {
printf("%05d %d -1", v[l].pre, v[l].data);
break;
}
printf("%05d %d %05d\n", v[l].pre, v[l].data, v[r - 1].pre);
count++;
l++, r--;
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
struct node {
int data;
int next;
}list[100000];
vector<int>v[3]; //总共有三种元素,小于【0,k】为在首位置,在[0,k]在中间,大于k在后
int main()
{
int first = 0, K = 0, N = 0;
cin >> first >> N >> K;
for (int i = 0; i < N; i++)
{
int temp = 0;
cin >> temp;
cin >> list[temp].data >> list[temp].next;
}
int p = first;
while (p != -1)
{
int count = list[p].data;
if (count < 0) v[0].push_back(p);
else if (count >= 0 && count <= K) v[1].push_back(p);
else if (count > K) v[2].push_back(p);
p = list[p].next;
}
int flag = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < v[i].size(); j++)
{
if (flag == 0)
{
printf("%05d %d ", v[i][j], list[v[i][j]].data);
flag = 1;
}
else {
printf("%05d\n%05d %d ", v[i][j], v[i][j], list[v[i][j]].data);
}
}
}
cout << "-1" << endl;
return 0;
}
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
int main()
{
int N = 0, K = 0,first = 0;
cin >> first >> N >> K;
int data[100010] = {
0 }, next[100010] = {
0 }, list[100010] = {
0 };
int temp = 0;
for (int i = 0; i < N; i++)
{
cin >> temp;
cin >> data[temp] >> next[temp];
}
int count = 0;
while (first != -1)
{
list[count++] = first;
first = next[first];
}
for (int i = 0; i <(count - (count % K)); i += K)
{
reverse(list + i, list + i + K);
}
for (int i = 0; i < count - 1; i++)
{
printf("%05d %d %05d\n", list[i], data[list[i]], list[i + 1]);
}
printf("%05d %d -1", list[count - 1], data[list[count - 1]]);
return 0;
}
3、中缀表达式转后缀表达式,并计算结果
从头到尾读取中缀表达式的每个对象,对不同的对象按不同的情况处理。(符号入栈,出栈,数据直接输出,运算符用栈,把后缀表达式用数组或队列存放)
运算数:直接输出
左括号:压入栈
右括号:将栈顶的运算符弹出并输出,直到遇到左括号(括号出栈但是不输出)
运算符;如果优先级大于栈顶运算符时,则把他压入栈;若优先级小于等于栈顶运算符的优先级,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压入栈;
若个对象处理完毕,则把堆栈中存留的运算符一并输出。
计算后缀表达式:从左到右一次扫描后缀表达式,如果是操作数,就压入栈,如果是操作符,就连续弹出两个操作数(后弹出的是第一个操作数,第一个弹出的是第二个操作数),然后进行操作符的操作,生成新的操作数压入栈中。反复直到后缀表达式扫描完毕,这是栈中只有一个数,就是最终答案。(除法可能导致浮点数,因此将其设成浮点型变量)
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include <cstring>
#include <string>
#include <stack>
#include<queue>
using namespace std;
struct node {
double num; //操作数
char op; //运算符
bool flag; //ture 为操作数,false为运算符
};
string str;//输入表达式
stack <node> s;//堆栈,用来云中缀表达式的运算符,和后缀表达式的操作数
queue<node> q; //用来表示后缀表达式
map<char, int> mp; //运算符的优先级
void Change()
{
double num;
node temp;
for (int i = 0; i < str.length();)
{
if (str[i] >= '0' && str[i] <= '9') {
temp.flag = true;//标记是数字
temp.num = str[i++] - '0';
while (i < str.length() && str[i] >= '0' && str[i] <= '9') {
temp.num = temp.num * 10 + (str[i] - '0');
i++;
}
q.push(temp);//操作数压入后缀表达式队列中
}
else {
temp.flag = false;
//只要操作符栈顶元素比该操作符优先级高,就把该操作符栈顶元素弹出到后缀表达式队列中国
while (!s.empty() && mp[str[i]] <= mp[s.top().op]) {
q.push(s.top());
s.pop();
}
temp.op = str[i];
s.push(temp);//把该操作符压入操作符栈中
i++;
}
}
while (!s.empty()) {
q.push(s.top());
s.pop();
}
}
double Cal() //计算后缀表达式
{
double temp1, temp2;
node cur, temp;
while (!q.empty()) //对列不为空
{
cur = q.front();
q.pop();
if (cur.flag) s.push(cur);//如果是操作数,则入栈
else {
temp2 = s.top().num;//弹出第二个操作数
s.pop();
temp1 = s.top().num;
s.pop();
temp.flag = true; //临时记录操作数
if (cur.op == '+') temp.num = temp1 + temp2;
else if (cur.op == '-') temp.num = temp1 - temp2;
else if (cur.op == '*') temp.num = temp1 * temp2;
else temp.num = temp1 / temp2;
s.push(temp); //压入栈
}
}
return s.top().num;//栈顶元素几位后缀表达式
}
int main()
{
mp['+'] = mp['-'] = 1;
mp['*'] = mp['/'] = 2;
while(getline(cin, str) && str != "0")
{
for (int i = 0; i < str.length();i++)
{
if (str[i] == ' ') str.erase(i,1); //去除多余空格
}
while (!s.empty()) s.pop();//初始化栈堆
Change();//将中缀表达式转为后缀表达式
node t;
/*
while(!q.empty())
{
t = q.front();
if (t.flag) {
printf("%.f ", t.num);
}
else {
printf("%c ", t.op);
}
q.pop();
}
*/
printf("%.2f\n", Cal()); //计算后缀表达式
}
return 0;
}
4、队列应用
约瑟夫问题:n个人围成圈,从第一个人开始报数,直到报出m,该人出列,下个人接着从1开是报
提供两种思路(一、队列法,二、纯模拟法)
一、队列法;先把所有数据入队,然后设一变量从1开始,当遇到m,就删去当前队列首元素,并让该变量等于1,当没遇到m,就不断让该变量自加,删除队首元素,并让被删除的队首元素压入队列到队尾,完成循环出队入队
二、纯模拟法:用有n个人,直到有n个人完全出去才算结束,这是外循环,内循环用for循环,让m != 从一开始自加的变量,为循环条件,表达式为,如果该数值出现过,就让其变为-1,并结束此循环,没出现,开变量i增加到那个地步,当为n时,用 i%= m;达到循环效果,如果变量等于m,就让次数据输出,并让器改值变为-1,表示用过该数据了。
//模拟,
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
int a[110] = { 0 };
int main()
{
int n = 0, m = 0;
cin >> n >> m;
int num = n,last = 1;//last是用来记录下一个人的位置
while (num)
{
int count = 0;
for (int i = last; count != m; i++)
{
if (i > n) i %= n;
if (a[i] == -1) continue;
++count;
if (count == m)
{
a[i] = -1;
printf("%d ", i);
last = i + 1;
num--;//人数少一个
break;
}
}
}
return 0;
}
//队列
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
queue<int>q;
int main()
{
int n = 0, m = 0;
cin >> n >> m;
int ans = 1;
for (int i = 1; i <= n; i++)
{
q.push(i);
}
while (!q.empty())
{
if (ans == m)
{
ans = 1;
int temp = q.front();
q.pop();
printf("%d ", temp);
}
else {
ans++;
q.push(q.front());
q.pop();
}
}
return 0;
}
5、双向链表
//队列
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
struct node {
int r;
int l;
int flag;
}k[100010];
int main()
{
int n, m, x, y, count = 0;
cin >> n;
k[1].l = 0, k[1].r = -1, k[1].flag = 1;
k[0].r = 1, k[0].flag = 1;//带头结点的双向链表
for (int i = 2; i <= n; i++) //结点的插入
{
cin >> x >> y;
k[i].flag = 1;
if (y == 0) //往右插入
{
k[k[x].l].r = i; //双向链表的插入过程
k[i].l = k[x].l;
k[i].r = x;
k[x].l = i;
}
else {
if (k[x].r != -1)
{
k[k[x].r].l = i;
k[i].r = k[x].r;
k[i].l = x;
k[x].r = i;
}
else {
k[x].r = i;
k[i].l = x;
k[i].r = -1;
}
}
}
cin >> m;
for (int i = 0; i < m; i++)//删除的过程
{
cin >> x;
if (k[x].flag == 1)//该数据第一次出现
{
k[x].flag = 0;
k[k[x].l].r = k[x].r;
k[k[x].r].l = k[x].l;
count++;//删除数据的个数
}
}
//cout << "count = " << count << endl;
int pr = 0, p = k[pr].r;
for (int i = 0; i < n - count; i++)
{
cout << p << " ";
pr = p;
p = k[pr].r;
}
return 0;
}
6、栈的应用
递归思路(dfs),递归实现
1.递归参数分别是栈中元素个数,进栈指针,出栈指针
2.递归边界是,当进栈指针和出栈指针同时满的时候(此时也是一种方案形成的时候)
3.递归子式;当进栈指针小于n时,栈元素数量增加一,进栈指针加一,出栈指针不变,出栈指针小于n时,栈中元素减一(且栈非空,否则不能减),出栈指针加一,进栈指针不变。
#include <iostream>
#include <cstdio>
#include <map>
#include <string>
#include <queue>
#include <algorithm>
#include<cmath>
using namespace std;
int n = 0, ans = 0;
void dfs(int num, int push, int pop)
{
if (push == n && pop == n)
{
ans++;
return;
}
if (push < n ) {
dfs(num + 1, push + 1, pop);
}
if (pop < n && num > 0) {
//栈中元素非空
dfs(num - 1, push, pop + 1);
}
}
int main()
{
cin >> n;
dfs(0, 0, 0);
printf("%d", ans);
return 0;
}
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
stack<int>s;
int main()
{
int q = 0, n = 0;
cin >> q;//询问次数
while (q--)
{
cin >> n;
int a[100010], b[100010], count = 1; //输 入栈序列,待验证序列,队b序列计数
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) cin >> b[i];
for (int i = 1; i <= n; i++)
{
s.push(a[i]); //入栈
while (s.top() == b[count]) //相等的话,栈顶元素与当前元素同时出栈
{
s.pop();
count++;//count到b的下一个元素
if (s.empty()) break;
}
}
if (s.empty()) cout << "Yes" << endl;
else cout << "No" << endl;
while (!s.empty()) s.pop();//清空栈元素
}
return 0;
}
十一、递归
分治思想;1、把一个庞大的问题,分解成若干子问题; 2、决绝每个小问题、3、合并
递归;反复调用自己的函数,是范围缩小,解决问题后,在一次往上返回
递归重要思想;1、寻找递归边界,并明确找到递归边界后做什么
2找递归式,找到递归式后做什么
全排列问题
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
int p[100]; //存放 当前排列
int n = 0;
int hashtable[100] = {
false}; //判段某数字在当前位是否出现过
void dfs(int index) //index 处理当前排列
{
if(index == n + 1) //递归边界,且还要直到做什么
{
for(int i = 1; i <= n; i++) //找到递归边界后,知道了存放排列值满员了,输出即可
{
if(i == 1) cout << p[i];
else cout << " " << p[i];
}
cout << endl;
return ;//开始往回返
}
for(int i = 1; i <= n; i++) //寻找1 ~ n开头的排列式子
{
if(hashtable[i] == false) //表明该数字还没存入p中
{
hashtable[i] = true;
p[index] = i;
dfs(index + 1); //处理index + 1 号排列
hashtable[i] = false; //处理完p[index]位x的子问题,还原状态。
}
}
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
n! = (n - 1)! * n;
#include <iostream>
#include <cstdio>
#include <map>
#include <algorithm>
#include <set>
#include <vector>
#include <cmath>
#include<stack>
#include<queue>
#include <cstring>
#include <string>
using namespace std;
int dfs(int n)
{
if(n == 1) return 1;
else{
return dfs(n - 1) * n;
}
}
int main()
{
int n = 0;
cin >> n;
printf("%d",dfs(n));
return 0;
}
斐波那契数列
#include <iostream>
using namespace std;
int fib(int n)
{
if(n == 1 || n == 0) return 1;
else{
return fib(n- 1) + fib(n - 2);
}
}
int main()
{
int n = 0;
cin >> n;
printf("%d",fib(n));
return 0;
}
汉诺塔问题
#include <cstdio>
#include<iostream>
using namespace std;
int h(int n)
{
if (n == 1) return 1;
else {
return (2 * h(n - 1) + 1);
}
}
int main()
{
int n = 0;
cin >> n;
cout << h(n);
return 0;
}
汉诺塔问题||
#include <cstdio>
#include<iostream>
using namespace std;
int count = 0; //每移动一次,就是一步,
void h(int n, char a, char b, char c) //由a经由b,到c
{
if (n == 1)
{
cout << n << " " << a << " -> " << c << endl; //只有一个盘子,直接由a飞到c即可
count++;
}
else {
h