王道考研系列 计算机考研 ——机试指南(第二版) 笔记(一)

article/2025/8/25 21:55:42

计算机机试,王道机试指南(第二版)笔记

机试指南一些笔记。。。
题目代码github链接
https://github.com/BenedictYoung
链接

视频 and pdf
链接:https:
//pan.bai
du.
com/s/1WFl
E5hWgg
Y9c3J97
fVbsRg?pwd=
xwep
提取
码:xw
ep

文章目录

  • 计算机机试,王道机试指南(第二版)笔记
  • 第六章 数学问题
    • 6.1 进制转换
      • 例题 6.1 二进制数(北京邮电大学复试上机题)
      • 例题 6.1 八进制(任意十进制内)
      • 例题 6.1 通用10以上进制
      • 习题 6.3 进制转换(从M进制转换为十进制通用代码)
      • 例题 6.4 进制转换2
      • 例题 6.1 进制转换(清华大学复试上机题)
      • 习题 6.2 又一版 A+B
      • 习题6.4 数制转换
    • 6.2 GCD&LCM(最大公约数And最小公倍数)
      • 例题 6.5 最大公约数
      • 例题 6.6 最小公倍数
      • 习题 6.5 最简真分数
    • 6.3 质数(Prime Number)
      • 例题 6.7 素数判定
      • 例题 6.2.3.2 Prime Number
      • 例题 6.2.3.3 素数
      • 例题 6.2.3.2 质因数的个数
      • 例题 6.2.3.3 约数的个数
      • 例题 6.2.3.2 整除问题
    • 6.4 快速幂运算
      • 6.2.3.1 快速幂
    • 6.4 矩阵
      • 6.4.1 计算两个矩阵的乘积
      • 6.4.1 矩阵幂
      • 6.4.3 A+B for Matrices
      • 6.4.3 习题 6.11 递归数列
    • 6.6 高精度整数
      • 例题6.13 a+b
      • 例题6.14 N的阶乘
      • 习题6.13 大整数的因子
  • 第七章 贪心策略
    • 7.1 简单贪心
      • 例题7.1 鸡兔同笼
      • 例题7.2 FatMouse' Trade
      • 例题7.3 Senior's Gun
      • 例题7.3 箱子打包
      • 习题 7.1 代理服务器
      • 例题7.4 Aggressive cows
      • 例题7.5 Drying
      • 习题 7.1 代理服务器(清华大学复试上机器)
    • 7.2 区间贪心
      • 7.1.1 例题7.4 今年暑假不AC
      • 7.1.1 POJ 1328 Radar Installation
      • 习题 7.2 To Fill or Not to Fill(浙江大学复试上机题)
  • 第八章 递归与分治
    • 8.1 递归策略
      • 8.1.1 n的阶乘
      • 8.1.2 汉诺塔
      • 习题 8.1 杨辉三角形 略
      • 习题 8.2 全排列(北京大学复试上机题) (Ex:全排列函数 + auto)
    • 8.2 分治法
      • 8.2.1 Fibonacci
      • 8.2.2 二叉树
      • 习题 8.3 2的幂次方 (上海交通大学复试上机题)
  • 第九章 搜索
    • 9.1 BFS
      • 例题 9.1.1 Catch That Cow
      • 例题 9.1.2 Find The Multiple
      • 小结
      • 习题 9.1 玛雅人的密码(清华大学复试上机题)
    • 9.2 DFS(深度优先遍历)
      • 例题 9.3 A Knight's Journey
      • 例题 9.4 Square
      • 习题 9.2.1 八皇后
  • 第十章 数据结构二
    • 10.1 二叉树
      • 10.1.1 例10.1 二叉树遍历(清华大学复试上机题)
      • 10.1.2 例10.2 二叉树遍历(华中科技大学复试上机题)
    • 10.2 二叉排序树
      • 例题10.3 二叉排序树(华中科技大学复试上机题)
      • 例题10.4 二叉排序树(华中科技大学复试上机题)
      • 习题 10.1 二叉搜索树
    • 10.3 优先队列
      • 例题10.5 复数集合
      • 例题10.6 哈夫曼树
      • 习题 10.3 查找第K小的数(北京邮电大学复试上机题)
      • 习题 10.3 搬水果(吉林大学复试上机题)
    • 10.4 散列表(map,unordered_map)
      • 10.4.1 例题10.7 查找学生信息
      • 10.4.2 例题10.8 魔咒词典(浙江大学复试上机题)
      • 10.4.3 例题10.8 子串计算(北京大学复试上机题)
      • 10.4.4 习题 10.4 统计同成绩学生人数(浙江大学复试上机题)
      • 10.4.5 习题 10.5 开门人和关门人(浙江大学复试上机题)
      • 10.4.6 习题 10.6 谁是你的潜在朋友(北京大学复试上机题)
  • 第十一章 图论问题
    • 11.1 概述
    • 11.2 并查集
      • 11.2.1 例题11.2 连通图
      • 11.2.2 例题11.1 畅通工程(浙江大学上机题)
      • 11.2.3 例题11.3 Is It A Tree(北京大学上机题)
      • 11.2.4 习题11.1 找出直系亲属(浙江大学复试上机题)
      • 11.2.5 习题11.2 第一题(上海交通大学复试上机题)
      • 11.2.6 习题11.3 Head of a Gang(浙江大学复试上机题)
    • 11.3 最小生成树
      • 11.3.1 例题11.4 还是畅通工程
      • 11.3.3 例题11.5 继续畅通工程
      • 11.3.4 习题11.4 Freckles
    • 11.4 最短路径
      • 11.4.1 畅通工程续
      • 11.4.2 例题11.7 最短路径问题
      • 11.4.3 习题11.6 最短路径(上海交通大学复试上机题)
      • 11.4.4 习题11.7 I Wanna Go Homw(北京大学复试上机题)
    • 11.5 拓扑排序
      • 11.5.1 例题 11.9 确定比赛名次
      • 11.5.2 例题 11.8 Legal or Not(拓扑排序判环)
    • 11.6 关键路径
      • 11.6.1 例题11.10 Instructions Arrangement
    • 11.7 小结


第六章 数学问题

6.1 进制转换

例题 6.1 二进制数(北京邮电大学复试上机题)

链接:https://www.nowcoder.com/practice/103dd589fed14457a673c613d8de3841?tpId=40&tqId=21519&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

· 描述

大家都知道,数据在计算机里中存储是以二进制的形式存储的。 有一天,小明学了C语言之后,他想知道一个类型为unsigned int 类型的数字,存储在计算机中的二进制串是什么样子的。 你能帮帮小明吗?并且,小明不想要二进制串中前面的没有意义的0串,即要去掉前导0。

· 输入描述:

多行,每一行表示要求的数字

· 输出描述:

输出共T行。每行输出求得的二进制串。

· 示例1

· 输入:
23
535
2624
56275
989835

· 输出:
10111
1000010111
101001000000
1101101111010011
11110001101010001011

· 分析

本题是一道十进制转换成二进制数的经典题目,主需要将数字n不断进行对2取模和对2整除运算,便可以得到各个数位的值。但是要注意,这种方法求出的数位顺序是从b0到bn,而数字输出需要的数位顺序是从bn到b0,因此在求出各个数位的值后,要将结果逆序输出。

代码如下(示例):

#include <iostream>
#include <cstdio>
#include <vector>using namespace std;int main(){unsigned int n;while(scanf("%d",&n)!=EOF){vector<int> binary;while(n!=0){binary.push_back(n%2);n/=2;}for(int i = binary.size()-1;i>=0;--i){//逆序输出printf("%d",binary[i]);}printf("\n");}return 0;
}

例题 6.1 八进制(任意十进制内)

链接:https://www.nowcoder.com/practice/eda051c1effc4dffa630bc8507f0c5f7?tpId=40&tqId=21562&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

· 描述

输入一个整数,将其转换成八进制数输出。

· 输入描述:

输入包括一个整数N(0<=N<=100000)。

· 输出描述:

可能有多组测试数据,对于每组数据, 输出N的八进制表示数。

示例1
输入:
7
8
9

输出:
7
10
11

分析:将上述代码稍加修改,将2改为10以内任意进制参数即可。

代码如下(示例):

#include <iostream>
#include <cstdio>
#include <vector>using namespace std;void ConvertT2N(int number,int n){//转换成为任意进制数vector<int> answer;if(number==0){//特殊用例number=0answer.push_back(0);}else{while(number!=0){//不断对2取模,求出二进制最末尾数字,随后除2answer.push_back(number%n);number/=n;}}for(int i = answer.size()-1;i>=0;i--){//逆序输出printf("%d",answer[i]);}printf("\n");
}
int main(){int number;while(scanf("%d",&number)!=EOF){ConvertT2N(number,8);//转换为八进制}return 0;
}

例题 6.1 通用10以上进制

说明:适用于十进制转换为其他进制类型,仅需要考虑数字到字符转换,vector容器转换为char类型,其他代码类似。

//例题 6.1 通用10以上进制
#include <iostream>
#include <cstdio>
#include <vector>using namespace std;char Int2Char(int target){//数字到字符转换if(target<10){return target+'0';}else{return target-10+'A';}
}
void ConvertT2N(int number,int n){//转换成为任意进制数vector<char> answer;//改为字符vector容器if(number==0){//特殊用例number=0answer.push_back('0');}else{while(number!=0){//不断对2取模,求出二进制最末尾数字,随后除2answer.push_back(Int2Char(number%n));number/=n;}}for(int i = answer.size()-1;i>=0;i--){//逆序输出printf("%c",answer[i]);}printf("\n");
}
int main(){int number;while(scanf("%d",&number)!=EOF){ConvertT2N(number,16);//转换为十以上进制}return 0;
}

习题 6.3 进制转换(从M进制转换为十进制通用代码)

链接:https://www.nowcoder.com/practice/deb19498bc644f53a6a99905ef5ee01d?tpId=40&tqId=21411&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

· 描述
写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串(注意可能存在的一个测试用例里的多组数据)。

· 输入描述:
输入一个十六进制的数值字符串。

· 输出描述:
输出该数值的十进制字符串。

· 示例1
输入:
0xA

输出:
10

说明:与上述思路类似,将十六进制数作为string类型输入,然后同上述思路相反,采用先乘以m,在加上该位对应的int数据。

#include <iostream>
#include <cstdio>using namespace std;int Char2Int(char target){//字符转换为数字if('0'<=target&&target<='9'){return target-'0';}else{return target-'A'+10;}
}
void ConvertM2T(string str,int m){//str表示M进制数,m为几进制int number=0;for(int i=0;i<str.size();i++){number*=m;//与十进制转换为M进制相反,为不断相乘,相加number+=Char2Int(str[i]);}printf("%d\n",number);
}
int main(){string str;while(cin>>str){str=str.substr(2);//去除0xConvertM2T(str,16);}return 0;
}

例题 6.4 进制转换2

从M进制转换为N进制

链接:https://www.nowcoder.com/practice/ae4b3c4a968745618d65b866002bbd32?tpId=40&tqId=30990&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

思路:将上述两种代码结合起来,先将M进制数字转换为十进制,再将十进制转换为N进制即可。

//从M进制转换为N进制
//例题6.4
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>using namespace std;char Int2Char(int target){//数字转换为字符if(target<10){return target+'0';}else{return target-10+'a';}
}
int Char2Int(char target){//字符转换为数字if('0'<=target&&target<='9'){return target-'0';}else{return target-'A'+10;}
}
long long ConvertM2T(string str,int m){long long number=0;for(int i=0;i<str.size();i++){number*=m;number+=Char2Int(str[i]);}return number;
}
void ConvertT2N(long long number,int n){//转换成为任意进制数vector<int> answer;if(number==0){//特殊用例number=0answer.push_back(0);}else{while(number!=0){//不断对2取模,求出二进制最末尾数字,随后除2answer.push_back(number%n);number/=n;}}for(int i = answer.size()-1;i>=0;i--){//逆序输出printf("%d",answer[i]);}printf("\n");
}
int main(){int m,n;while(scanf("%d%d",&m,&n)!=EOF){string str;cin>>str;long long number=ConvertM2T(str,m);//由于数据范围较大,采用long long类型ConvertT2N(number,n);}
}

例题 6.1 进制转换(清华大学复试上机题)

链接:https://www.nowcoder.com/practice/0337e32b1e5543a19fa380e36d9343d7?tpId=40&tqId=21332&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

· 描述

将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。

· 输入描述:

多组数据,每行为一个长度不超过30位的十进制非负整数。 (注意是10进制数字的个数可能有30个,而非30bits的整数)

· 输出描述:

每行输出对应的二进制数。

· 分析

由于输入的位数多达30位,因此采用字符串string模拟的数字不断进行对2取模和对2整除运算,即可求出结果。
对于取模运算,可以将其转换为对字符串中的最低数位进行取模运算,二者在功能上是等价的。

代码如下(示例):

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>using namespace std;string Divide(string str,int x){ //字符串除法int remainder = 0;  //保留余数for(int i=0;i<str.size();i++){int current=remainder*10+str[i]-'0';str[i]=current/x+'0';remainder=current%x;}int pos=0;while(str[pos]=='0'){  //寻找首个非零下标pos++;}return str.substr(pos);  //删除前置多余的0
}
int main(){string str;while(cin>>str){vector<int> binary;while(str.size()!=0){int last=str[str.size()-1]-'0';  //最低位的值binary.push_back(last%2);  //取模运算str=Divide(str,2);  //整除运算}for(int i=binary.size()-1;i>=0;i--){printf("%d",binary[i]);}printf("\n");}return 0;
}

习题 6.2 又一版 A+B

题目链接

注意特殊用例,输入AB为0 0时候,应该结果输出0。

#include <iostream>
#include <string>
#include <cstdio>
#include <vector>using namespace std;void ToM(long long n,int m){vector <int>answer;if(n==0){answer.push_back(0);//注意0的特殊用例}while(n!=0){answer.push_back(n%m);n/=m;}for(int i=answer.size()-1;i>=0;i--){printf("%d",answer[i]);}printf("\n");
}int main(){long long m,A,B;while(cin>>m>>A>>B){if(m==0){break;}long long res=A+B;ToM(res,m);}return 0;
}

习题6.4 数制转换

题目链接

#include <iostream>
#include <string>
#include <cstdio>
#include <vector>
using namespace std;long Char2Int(char c){if(c>='0'&&c<='9'){return c-'0';}else if(c>='A'&&c<='F'){return c-'A'+10;}else{return c-'a'+10;}
}
char Int2Char(long number){if(number>=0&&number<=9){return number+'0';}else{return number-10+'A';}
}long ToD(string str,int m){//m进制转换为十进制long number=0;for(int i=0;i<str.size();i++){number*=m;number+=Char2Int(str[i]);}return number;
}void ToM(long num,int m){//十进制转换为m进制vector<char> res;if(num==0){res.push_back('0');}while(num!=0){res.push_back(Int2Char(num%m));num/=m;}for(int i=res.size()-1;i>=0;i--){printf("%c",res[i]);}printf("\n");
}int main(){int a,b;string n;cin>>a>>n>>b;ToM(ToD(n,a),b);
}

6.2 GCD&LCM(最大公约数And最小公倍数)

思想:辗转相除法(欧几里得法)

例题 6.5 最大公约数

链接:https://www.nowcoder.com/practice/20216f2c84bc438eb5ef05e382536fd3?tpId=40&tqId=21492&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan&difficulty=&judgeStatus=&tags=/question-ranking

描述

输入两个正整数,求其最大公约数。

输入描述:

测试数据有多组,每组输入两个正整数。

输出描述:

对于每组输入,请输出其最大公约数。

示例1
输入:
49 14
输出:
7

#include <iostream>
#include <cstdio>using namespace std;int GCD(int a,int b){if(b==0){return a;}else{return GCD(b,a%b);}
}
int main(){int a,b;while(scanf("%d%d",&a,&b)!=EOF){printf("%d\n",GCD(a,b));}
}

例题 6.6 最小公倍数

思路:a * b /gcd(a,b)
杭电oj题,进不去。。。

#include <iostream>
#include <cstdio>using namespace std;int GCD(int a,int b){if(b==0){return a;}else{return GCD(b,a%b);}
}
int main(){int a,b;while(scanf("%d%d",&a,&b)!=EOF){printf("%d\n",a*b/GCD(a,b));//修改这里即可}
}

习题 6.5 最简真分数

题目链接

淦,别写死循环,被测试用例误导了,以为n==0跳出,以后输入测试样例还是用while(scanf()!=EOF

#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=600+10;int arr[600+10];int GCD(int a,int b){if(b==0){return a;}return GCD(b,a%b);
}bool isReal(int x,int y){return GCD(x,y)==1;
}int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}for(int i=0;i<n;i++){scanf("%d",&arr[i]);}int cnt=0;sort(arr,arr+n);for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){if(isReal(arr[i],arr[j])){cnt++;}}}printf("%d\n",cnt);}return 0;
}

6.3 质数(Prime Number)

例题 6.7 素数判定

题目链接

说明:只需要判定到根号n为上界即可,但是注意要包括根号n判定

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;bool Judge(int n){if(n<2){return false;}int bound=sqrt(n);//上界为根号nfor(int i=2;i<=bound;i++){//注意这里要等于上界if(n%i==0){return false;}}return true;
}
int main(){int n;while(scanf("%d",&n)!=EOF){if(Judge(n)){printf("yes\n");}else{printf("no\n");}}}

例题 6.2.3.2 Prime Number

题目链接

质数筛法:不断将当前指针所指向的数字的倍数全部标记为非质数(从2开始)

#include <iostream>
#include <cstdio>
#include <vector>using namespace std;const int MAXN=1e5+10;vector<int> prime;
bool isPrime[MAXN];void Initial(){
//     for(int i=0;i<MAXN;i++){
//         isPrime[i]=true;
//     }
//    或者可以采用fill函数fill(isPrime,isPrime+MAXN,true);isPrime[0]=false;isPrime[1]=false;//0和1均为非质数for(int i=2;i<MAXN;i++){if(!isPrime[i]){continue;}prime.push_back(i);if(i>MAXN/i){//防止i*i出现溢出continue;}for(int j=i*i;j<MAXN;j+=i){isPrime[j]=false;}}
}
int main(){int k;Initial();while(scanf("%d",&k)!=EOF){printf("%d\n",prime[k-1]);}return 0;
}

例题 6.2.3.3 素数

题目链接

别忘了开始调用Initial()

#include <iostream>
#include <string>
#include <cstdio>
#include <vector>using namespace std;const int MAXN =1e5+10;bool isPrime[MAXN];vector <int>primes;//模板代码
void Initial(){for(int i=0;i<MAXN;i++){isPrime[i]=true;}isPrime[0]=false;isPrime[1]=false;//0,1不是质数for(int i=2;i<MAXN;i++){if(!isPrime[i]){continue;//如果当前数不是质数,略过,肯定它的倍数已经被处理过了}primes.push_back(i);for(int j=i*i;j<MAXN;j+=i){//注意这里可以从i*i开始处理,因为i*2-i*(i-1)肯定是被处理过了isPrime[j]=false;}}return;
}
int main(){int n;scanf("%d",&n);bool flag=false;Initial();//别忘了调用for(int i=0;i<primes.size();i++){if(primes[i]<n&&primes[i]%10==1){if(!flag){flag=!flag;printf("%d",primes[i]);}else{printf(" %d",primes[i]);}}}}

例题 6.2.3.2 质因数的个数

题目链接

质因子分解:短除法

短除法

#include <iostream>
#include <cstdio>
#include <vector>using namespace std;const int MAXN=4e4;//由于数据范围较大,大于10^9,因此这里只考虑根号10^9大约4e4,如果有大于根号n的情况,那么只会有且仅有一个这个因子,最后处理一下即可,在if(number>1)处理vector<int> prime;
bool isPrime[MAXN];void Initial(){
//     for(int i=0;i<MAXN;i++){
//         isPrime[i]=true;
//     }
//    或者可以采用fill函数fill(isPrime,isPrime+MAXN,true);isPrime[0]=false;isPrime[1]=false;//0和1均为非质数for(int i=2;i<MAXN;i++){if(!isPrime[i]){continue;}prime.push_back(i);if(i>MAXN/i){//防止i*i出现溢出continue;}for(int j=i*i;j<MAXN;j+=i){isPrime[j]=false;}}
}
int NumberOfPrimeFactors(int number){int answer=0;for(int i=0;i<prime.size();i++){int factor=prime[i];if(number<factor){break;}int exponent=0;while(number%factor==0){exponent++;number/=factor;}answer+=exponent;}if(number>1){//!!!如果number大于1时候,说明n此时还有一个大于根号n的质因子,还需要进行累加answer+=1;}return answer;
}int main(){Initial();int number;while(scanf("%d",&number)!=EOF){printf("%d\n",NumberOfPrimeFactors(number));}
}

例题 6.2.3.3 约数的个数

题目链接

分析1
例子
每个质因子都有ei+1种选择,因此对于每个质因子进行一种组合结果即为(e1+1)(e2+1)…(en+1)

#include <iostream>
#include <cstdio>
#include <vector>using namespace std;const int MAXN=4e4;vector<int> prime;
bool isPrime[MAXN];void Initial(){
//     for(int i=0;i<MAXN;i++){
//         isPrime[i]=true;
//     }
//    或者可以采用fill函数fill(isPrime,isPrime+MAXN,true);isPrime[0]=false;isPrime[1]=false;//0和1均为非质数for(int i=2;i<MAXN;i++){if(!isPrime[i]){continue;}prime.push_back(i);if(i>MAXN/i){//防止i*i出现溢出continue;}for(int j=i*i;j<MAXN;j+=i){isPrime[j]=false;}}
}
int NumberOfFactors(int number){int answer=1;for(int i=0;i<prime.size();i++){int factor=prime[i];if(number<factor){break;}int exponent=0;while(number%factor==0){exponent++;number/=factor;}answer*=(exponent+1);}if(number>1){answer*=2;}return answer;
}int main(){Initial();int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}for(int i=0;i<n;i++){int number;scanf("%d",&number);printf("%d\n",NumberOfFactors(number));}}
}

例题 6.2.3.2 整除问题

题目链接
思路来自题解

思路

#include <iostream>
#include <vector>
#include <cstring>using namespace std;const int MAXN=1000+10;int factorOfn[MAXN];//质因子出现个数
int factorOfa[MAXN];int main(){int n,a;scanf("%d %d",&n,&a);memset(factorOfa,sizeof(factorOfa),0);memset(factorOfn,sizeof(factorOfn),0);for(int i=2;i<=n;i++){//对于2-n中每个数字进行处理(n!)int tmp=i;//存储一下ifor(int j=2;j*j<=i;j++){//找出质因子while(i%j==0){//每个质因子进行计数factorOfn[j]++;i/=j;}}if(i>1){//剩下质因子factorOfn[i]++;}i=tmp;}//求解质因子情况代码模板for(int i=2;i*i<=a;i++){while(a%i==0){factorOfa[i]++;a/=i;}}if(a>1){factorOfa[a]++;}int k=1e6;for(int i=0;i<MAXN;i++){if(factorOfa[i]){k=min(k,factorOfn[i]/factorOfa[i]);}}printf("%d",k);
}

6.4 快速幂运算

6.2.3.1 快速幂

快速幂
模板代码

int QuickPower(int x,int n){//求x的n次幂(模板)int answer=1;while(n!=0){if(n%2==1){answer*=x;}n/=2;x*=x;}return answer;
}

杭电oj 2035题
Tip:需要进行模运算处理

#include <iostream>
#include <cstdio>using namespace std;int QuickPower(int x,int n){//求x的n次幂(模板)int mod=1000;int answer=1;while(n!=0){if(n%2==1){answer*=x;answer%=mod;}n/=2;x*=x;x%=mod;}return answer;
}
int main(){int a,b;while(scanf("%d%d",&a,&b)!=EOF){if(a==0&&b==0){break;}printf("%d\n",QuickPower(a, b));}return 0;
}

6.4 矩阵

6.4.1 计算两个矩阵的乘积

题目链接

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=100;//用二维数组模拟矩阵
//矩阵定义
struct Matrix{int row,col;int matrix[MAXN][MAXN];Matrix(){}Matrix(int r,int c):row(r),col(c){}
};//矩阵相加
Matrix Add(Matrix x,Matrix y){Matrix answer=Matrix(x.row,x.col);for(int i=0;i<answer.row;i++){for(int j=0;j<answer.col;j++){answer.matrix[i][j]=x.matrix[i][j]+y.matrix[i][j];}}return answer;
}//矩阵相乘
Matrix Multiply(Matrix x,Matrix y){Matrix answer=Matrix(x.row,y.col);for(int i=0;i<answer.row;i++){for(int j=0;j<answer.col;j++){answer.matrix[i][j]=0;for(int k=0;k<x.col;k++){answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];}}}return answer;
}//矩阵转置
Matrix Transpose(Matrix x){Matrix answer=Matrix(x.col,x.row);for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){answer.matrix[j][i]=x.matrix[i][j];}}return answer;
}//矩阵求幂,采用快速幂运算
Matrix QuickPower(Matrix x,int n){Matrix answer=Matrix(x.row,x.col);for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){if(i==j){answer.matrix[i][j]=1;}else{answer.matrix[i][j]=0;}}}while(n!=0){if(n%2==1){answer=Multiply(answer,x);}n/=2;x=Multiply(x,x);}return answer;
}//矩阵输入
void InputMatrix(Matrix& x){for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){scanf("%d",&x.matrix[i][j]);}}return;
}//矩阵输出
void OutputMatrix(Matrix x){for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){if(j==0){printf("%d",x.matrix[i][j]);}else{printf(" %d",x.matrix[i][j]);}}printf("\n");}return;
}int main(){Matrix x(2,3);Matrix y(3,2);InputMatrix(x);InputMatrix(y);Matrix answer=Multiply(x,y);OutputMatrix(answer);return 0;
}

6.4.1 矩阵幂

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=100;//用二维数组模拟矩阵
//矩阵定义
struct Matrix{int row,col;int matrix[MAXN][MAXN];Matrix(){}Matrix(int r,int c):row(r),col(c){}
};//矩阵相加
Matrix Add(Matrix x,Matrix y){Matrix answer=Matrix(x.row,x.col);for(int i=0;i<answer.row;i++){for(int j=0;j<answer.col;j++){answer.matrix[i][j]=x.matrix[i][j]+y.matrix[i][j];}}return answer;
}//矩阵相乘
Matrix Multiply(Matrix x,Matrix y){Matrix answer=Matrix(x.row,y.col);for(int i=0;i<answer.row;i++){for(int j=0;j<answer.col;j++){answer.matrix[i][j]=0;for(int k=0;k<x.col;k++){answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];}}}return answer;
}//矩阵转置
Matrix Transpose(Matrix x){Matrix answer=Matrix(x.col,x.row);for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){answer.matrix[j][i]=x.matrix[i][j];}}return answer;
}//矩阵求幂,采用快速幂运算
Matrix QuickPower(Matrix x,int n){Matrix answer=Matrix(x.row,x.col);for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){if(i==j){answer.matrix[i][j]=1;}else{answer.matrix[i][j]=0;}}}while(n!=0){if(n%2==1){answer=Multiply(answer,x);}n/=2;x=Multiply(x,x);}return answer;
}//矩阵输入
void InputMatrix(Matrix& x){for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){scanf("%d",&x.matrix[i][j]);}}return;
}//矩阵输出
void OutputMatrix(Matrix x){for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){if(j==0){printf("%d",x.matrix[i][j]);}else{printf(" %d",x.matrix[i][j]);}}printf("\n");}return;
}int main(){int n,k;while(scanf("%d%d",&n,&k)!=EOF){Matrix x=Matrix(n,n);InputMatrix(x);Matrix answer=QuickPower(x,k);OutputMatrix(answer);}return 0;
}

6.4.3 A+B for Matrices

链接

#include <iostream>
#include <string>using namespace std;const int MAXN=10+5;struct Matrix{int row,col;int element[MAXN][MAXN];Matrix(){}Matrix(int x,int y):row(x),col(y){}
};Matrix add(Matrix A,Matrix B){Matrix answer=Matrix(A.row,A.col);for(int i=0;i<A.row;i++){for(int j=0;j<A.col;j++){answer.element[i][j]=A.element[i][j]+B.element[i][j];}}return answer;
}void input(Matrix& A){for(int i=0;i<A.row;i++){for(int j=0;j<A.col;j++){scanf("%d",&A.element[i][j]);}}
}int count(Matrix A){int cnt=0;for(int i=0;i<A.row;i++){bool flag = false;for(int j=0;j<A.col;j++){if(A.element[i][j]!=0){flag = true;break;}}if(!flag){cnt++;}}for(int i=0;i<A.col;i++){bool flag = false;for(int j=0;j<A.row;j++){if(A.element[j][i]!=0){flag = true;break;}}if(!flag){cnt++;}}return cnt;
}int main(){int m,n;while(scanf("%d",&m)!=EOF){scanf("%d",&n);if(m==0){break;}Matrix A,B;A.row=B.row=m;A.col=B.col=n;input(A);input(B);Matrix C=add(A,B);printf("%d\n",count(C));}return 0;
}

6.4.3 习题 6.11 递归数列

题目链接

调试一下午。。

  1. 注意矩阵快速幂代码书写
Matrix QuickExpon(Matrix x,int k){Matrix answer;//注意这里要初始化成单位矩阵!!!!for(int i=0;i<2;i++){for(int j=0;j<2;j++){if(i==j){answer.element[i][j]=1;}else{answer.element[i][j]=0;}}}while(k){//这里不要搞错if(k%2){answer=Multiply(answer,x);}k/=2;x=Multiply(x,x);}return answer;
}
  1. 对于int类型输入用%d,long long输入采用%lld,对应输出同样
  2. 对于结果要取模,在运算过程中都要进行取模操作

思路:采用矩阵快速幂运算。详细问题可以参考
https://blog.csdn.net/csyifanZhang/article/details/104594647

AC代码:

#include <iostream>
#include <string>using namespace std;const int MAXN=2;
const int MOD=10000;typedef long long ll;struct Matrix{ll element[2][2];Matrix(){}
};Matrix Multiply(Matrix x,Matrix y){Matrix answer;for(int i=0;i<2;i++){for(int j=0;j<2;j++){ll sum=0;for(int k=0;k<2;k++){sum=(sum+x.element[i][k]*y.element[k][j])%MOD;}answer.element[i][j]=sum;}}return answer;
}Matrix QuickExpon(Matrix x,int k){Matrix answer;for(int i=0;i<2;i++){for(int j=0;j<2;j++){if(i==j){answer.element[i][j]=1;}else{answer.element[i][j]=0;}}}while(k){if(k%2){answer=Multiply(answer,x);}k/=2;x=Multiply(x,x);}return answer;
}void input(Matrix &x,ll a,int b,int c,int d){x.element[0][0]=a;x.element[0][1]=b;x.element[1][0]=c;x.element[1][1]=d;
}int main(){int a0,a1,p,q,k;scanf("%d %d %d %d %d",&a0,&a1,&p,&q,&k);Matrix answer,pq,start;input(pq,p,q,1,0);input(start,a1,0,a0,0);answer=Multiply(QuickExpon(pq,k-1),start);printf("%lld",answer.element[0][0]%MOD);return 0;
}

6.6 高精度整数

数字范围
在这里插入图片描述
解决方案

例题6.13 a+b

JAVA

import java.util.Scanner;
import java.math.BigInteger;public class Main{public static void main(String[] args){Scanner input=new Scanner(System.in);while(input.hasNext()){int n=input.nextInt();BigInteger answer=input.nextBigInteger();BigInteger b=input.nextBigInteger();System.out.println(a.add(b));}}
}

cpp 采用字符串string处理

#include <iostream>
#include <string>
#include <cstdio>using namespace std;string add(string a,string b){string answer;int carry=0;while(a.length()<b.length()){a.insert(0,1,'0');}while(a.length()>b.length()){b.insert(0,1,'0');}for(int i=a.length()-1;i>=0;i--){int r=(a[i]-'0')+(b[i]-'0')+carry;carry=r/10;char c=r%10+'0';answer.insert(0,1,c);}if(carry){answer.insert(0,1,'1');}return answer;
}
int main(){string a,b;while(cin>>a>>b){cout<<add(a,b)<<endl;}
}

cpp 结构体,数字数组进行处理

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>using namespace std;const int MAXN=10000;struct BigInteger{int digit[MAXN];int length;BigInteger();BigInteger operator=(string str);BigInteger operator+(const BigInteger& b);friend istream& operator>>(istream& in,BigInteger& x);friend ostream& operator<<(ostream& out,const BigInteger& x);
};istream& operator>>(istream&in,BigInteger &x){string str;in >> str;x = str;return in;
}ostream& operator<<(ostream& out,const BigInteger& x){for(int i=x.length-1;i>=0;i--){out<<x.digit[i];}return out;
}BigInteger::BigInteger(){memset(digit,0,sizeof(digit));length=0;
}BigInteger BigInteger::operator=(string str){memset(digit,0,sizeof(digit));length=str.size();for(int i=0;i<length;i++){digit[i]=str[length-i-1]-'0';}return *this;
}//template
BigInteger BigInteger::operator+(const BigInteger& b){BigInteger answer;int carry=0;for(int i=0;i<length||i<b.length;i++){int current=carry+digit[i]+b.digit[i];carry=current/10;answer.digit[answer.length++]=current%10;}if(carry!=0){answer.digit[answer.length++]=carry;}return answer;}int main(){BigInteger a;BigInteger b;while(cin>>a>>b){cout<<a+b<<endl;}return 0;
}

例题6.14 N的阶乘

习题6.13 大整数的因子

题目链接

大整数除法代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
//本题是大整数除法
int divideString(string a,int x)
{int remainder=0;for(int i=0;i<a.size();i++){int num=remainder*10+a[i]-'0';a[i]=num/x+'0';remainder=num%x;}return remainder;//求商返回a,求模返回remainder
} 
using namespace std;
int main()
{string c;while(cin>>c){if(c=="-1")break;int sum=0;for(int i=2;i<10;i++){if(divideString(c,i)==0){printf("%d ",i);sum++;}}if(!sum)printf("none\n");else printf("\n");        }return 0;
} 

第七章 贪心策略

贪心策略常用于求解最优化问题,其核心思想是,总是选择当前状态下最优的策略,也就说,它并不以整体最优进行考虑,而只考虑当前这一步。因此,这种方法能够得到局部最优解,在最后往往也能够获得全局最优解,但并不保证收敛到全局最优解。

7.1 简单贪心

例题7.1 鸡兔同笼

题目链接

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;int main(){int n;while(scanf("%d",&n)!=EOF){if(n%2){printf("0 0\n");}else{if(n%4==0){printf("%d %d\n",n/4,n/2);}else{printf("%d %d\n",n/4+1,n/2);}}}return 0;
}

例题7.2 FatMouse’ Trade

题目来源:杭电oj - 1009
Tip:
尽可能多的咖啡豆:贪心策略
注意:商品可以任意切分,无需买完
策略

#include <iostream>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=1000;struct JavaBean{double weight;double cost;
};JavaBean arr[MAXN];bool Compare(JavaBean x,JavaBean y){//比较性价比return x.weight/x.cost>y.weight/y.cost;
}int main(){int n,m;while(scanf("%d%d",&m,&n)!=EOF){if(n==-1&&m==-1){break;}for(int i=0;i<n;i++){scanf("%lf%lf",&arr[i].weight,&arr[i].cost);}sort(arr,arr+n,Compare);double answer=0;for(int i=0;i<n;i++){if(m>=arr[i].cost){m-=arr[i].cost;answer+=arr[i].weight;}else{answer+=arr[i].weight*(m/arr[i].cost);m=0;break;}}printf("%.3f",answer);}return 0;
}

例题7.3 Senior’s Gun

杭电oj - 5281
分析

#include <iostream>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=100000+10;long long gun[MAXN];
long long monster[MAXN];bool Compare(long long x,long long y){return x>y;
}int main(){int caseNumber;scanf("%d",&caseNumber);while(caseNumber--){int n,m;scanf("%d %d",&n,&m);for(int i=0;i<n;i++){scanf("%lld",&gun[i]);}for(int i=0;i<m;i++){scanf("%lld",&monster[i]);}sort(gun,gun+n,Compare);sort(monster,monster+m);long long answer=0;for(int i=0;i<n;i++){if(i>=m||gun[i]<=monster[i]){break;}answer+=gun[i]-monster[i];}printf("%lld",answer);}
}

例题7.3 箱子打包

ECNU 1045题
题目链接
箱子打包

#include <iostream>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=1e5+10;int length[MAXN];int main(){int n,l;scanf("%d%d",&n,&l);for(int i=0;i<n;i++){scanf("%d",&length[i]);}sort(length,length+n);int left=0;int right=n-1;int answer=0;while(left<=right){if(length[left]+length[right]<=l){left++;right--;}else{right--;}answer++;}printf("%d",answer);return 0;
}

习题 7.1 代理服务器

题目链接

思路:贪心(来自题解):
依次访问服务器servers,遇到代理则标记一下,
直到遇到一个代理A时全部代理都被标记过,这时认为之前都是用这个代理A进行访问的,
此时切换代理(次数+1)并清零A以外的标记,同样的,遇到代理标记一下,
直到遇到一个代理B时全部代理都被标记过,这时认为之前都是用这个代理B进行访问的,
切换代理(次数+1),以此类推……

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>using namespace std;const int MAXN=1000+10;vector<string> proxy;
vector<string> server;
int flag[MAXN];int main(){memset(flag, 0, sizeof(flag));int n,m;scanf("%d",&n);for(int i=0;i<n;i++){string str;cin>>str;proxy.push_back(str);}scanf("%d",&m);int answer=0;int index=0;int left=n;//剩余未被标记服务器数目for(int i=0;i<m;i++){string str;cin>>str;auto it=find(proxy.begin(),proxy.end(),str);if(it!=proxy.end()){//这是在vector中返回迭代器所指向的元素的下标的常用手段//使用当前迭代器减去起始迭代器//即是当前迭代器所指向的元素的下标index=it-proxy.begin();if(!flag[index]){flag[index]=1;left--;}}if(left==0){answer++;if(n==1){printf("-1");return 0;}memset(flag, 0, sizeof(flag));//最后一个被标记的代理服务器不能参与下次循环flag[index] = 1;left = n - 1;}}printf("%d",answer);return 0;
}

例题7.4 Aggressive cows

POJ 2456
题目链接

Tip:
最大的最小间距(类似的问题):二分策略

思路

#include <cstdio>
#include <iosteam>
#include <algorithm>using namespace std;const int MAXN=1e5+10;int arr[MAXN];bool Judge(int n,int m,int distance){int current=arr[0];int number=1;for(int i=1;i<n;i++){if(arr[i]-current>=distance){number++;current=arr[i];}if(number>=m){return true;}}return false;
}int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<n;i++){scanf("%d",&arr[i]);}sort(arr,arr+n);int left=1;int right=arr[n-1]-arr[0];while(left<=right){int middle=left+(right-left)/2;if(Judge(n,m,middle)){left=middle+1;}else{right=middle-1;}}printf("%d\n",right);}return 0;
}

例题7.5 Drying

POJ 3104
题目链接

说明
说明

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>using namespace std;const int MAXN=1e5+10;int water[MAXN];bool Judge(int n,int k,int time){int sum=0;for(int i=0;i<n;i++){if(water[i]>time){sum+=ceil((water[i]-time)*1.0/(k-1);//注意这里是k-1因为与此同时风干速度也是1//ceil为取上整数函数,相对应floor为取下整数,位于cmath中}if(sum>time){return false;}}return true;
}int main(){int n;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%d",&water[i]);}int k;scanf("%d",&k);sort(water,water+n);if(k==1){//烘干机能力为1时候,与空气无异,取决于最大水分那件衣服printf("%d\n",water[n-1]);}else{int left=1;int right=arr[n-1];while(left<=right){int middle=left+(right-left)/2;if(Judge(n,k,middle)){right=middle-1;}else{left=middle+1;}}printf("%d\n",left);}return 0;
}

习题 7.1 代理服务器(清华大学复试上机器)

题目链接

思路:贪心:
依次访问服务器servers,遇到代理则标记一下,
直到遇到一个代理A时全部代理都被标记过,这时认为之前都是用这个代理A进行访问的,
此时切换代理(次数+1)并清零A以外的标记,同样的,遇到代理标记一下,
直到遇到一个代理B时全部代理都被标记过,这时认为之前都是用这个代理B进行访问的,
切换代理(次数+1),以此类推……

#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <algorithm>using namespace std;const int MAXN=1000+10;vector<string> proxy;
vector<string> server;
int flag[MAXN];int main(){memset(flag, 0, sizeof(flag));int n,m;scanf("%d",&n);for(int i=0;i<n;i++){string str;cin>>str;proxy.push_back(str);}scanf("%d",&m);int answer=0;int index=0;int left=n;//剩余未被标记服务器数目for(int i=0;i<m;i++){string str;cin>>str;auto it=find(proxy.begin(),proxy.end(),str);if(it!=proxy.end()){//这是在vector中返回迭代器所指向的元素的下标的常用手段//使用当前迭代器减去起始迭代器//即是当前迭代器所指向的元素的下标index=it-proxy.begin();if(!flag[index]){flag[index]=1;left--;}}if(left==0){answer++;if(n==1){printf("-1");return 0;}memset(flag, 0, sizeof(flag));//最后一个被标记的代理服务器不能参与下次循环flag[index] = 1;left = n - 1;}}printf("%d",answer);return 0;
}

7.2 区间贪心

7.1.1 例题7.4 今年暑假不AC

杭电oj - 2037
思路:结束时间最早的。
思路

思路

#include <iostream>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=100+10;struct program{int startTime;int endTime;
};bool Compare(program x,program y){return x.endTime<y.endTime;
}program arr[MAXN];int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}for(int i=0;i<n;i++){scanf("%d%d",&arr[i].startTime,&arr[i].endTime);sort(arr,arr+n,Compare);int current=0;int answer=0;for(int i=0;i<n;i++){if(current<=arr[i].startTime){current=arr[i].endTime;answer++;}}}printf("%d",answer);}return 0;
}

7.1.1 POJ 1328 Radar Installation

题目链接
从雷达角度出发
思路:从岛屿出发分析,找到可以覆盖岛屿的区间。
从山角度出发
思路:
思路

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>using namespace std;const int MAXN=1000+10;struct Interval{double left;double right;
};Interval arr[MAXN];bool Compare(Interval a,Interval b){return a.left<b.left;
}int main(){int n,d;int caseNumber=0;while(scanf("%d%d",&n,&d)!=EOF){if(n==0&&d==0){break;}bool flag=true;//标记是否可以实现for(int i=0;i<n;i++){int x,y;scanf("%d%d",&x,&y);if(y>d){flag=false;}else{arr[i].left=x-sqrt(d*d-1.0*y*y);arr[i].right=x+sqrt(d*d-1.0*y*y);}}if(!flag){printf("Case %d: %d\n",++caseNumber,-1);}else{sort(arr,arr+n,Compare);double current=arr[0].right;int answer=1;for(int i=1;i<n;i++){if(arr[i].left<=current){current=min(current,arr[i].right);}else{current=arr[i].right;answer++;}}printf("Case %d: %d\n",++caseNumber,answer);}}return 0;
}

习题 7.2 To Fill or Not to Fill(浙江大学复试上机题)

题目链接
摆烂了。。太菜了我

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 510;
const int inf = 0x3fffffff;struct station{double price,dis;	//价格、与起点的距离 
}st[maxn];bool cmp(station a,station b){return a.dis < b.dis;	//按距离从小到大排序 
}int main(){int n;double Cmax,D,Davg;while(scanf("%lf%lf%lf%d",&Cmax,&D,&Davg,&n)!=EOF){for(int i=0;i<n;i++){scanf("%lf%lf",&st[i].price,&st[i].dis);}st[n].price = 0;	//数组最后面放置终点,价格为0st[n].dis = D;		//终点距离为Dsort(st,st+n,cmp);	//将所有加油站按距离从小到大排序if(st[0].dis != 0){	//如果排序后的第一个加油站距离不是0,说明无法前进 printf("The maximum travel distance = 0.00\n"); }else{int now=0;	//当前所处的加油站编号//总花费、当前油量及满油行驶距离double ans=0,nowTank=0,MAX=Cmax*Davg;while(now<n){	//每次循环将选出下一个需要到达的加油站 //选出从当前加油站满油能够到达范围内的一个油价低于当前油价的加油站//如果没有低于当前油价的加油站,则选择价格最低的那个int k=-1;	//最低油价的加油站的编号double priceMin = inf;for(int i=now+1;i<=n&&st[i].dis-st[now].dis<=MAX;i++){if(st[i].price < priceMin){priceMin = st[i].price;		//如果油价比当前最低油价低 k=i;	//更新最低油价//如果找到第一个油价低于当前油价的加油站,直接中断循环if(priceMin < st[now].price){break;} }}if(k == -1) break;	//无法找到加油站//下面为能找到可到达的加油站k,计算转移花费//need为从now到k需要的油量double need = (st[k].dis - st[now].dis) / Davg;if(priceMin < st[now].price){//只买足够到达加油站k的值if(nowTank < need){ans += (need-nowTank) * st[now].price;nowTank = 0; }else{nowTank -= need;} }else{	//注意这里的加满操作 ans += (Cmax-nowTank)*st[now].price;nowTank = Cmax-need;}now = k;	//到达加油站k,进入下一个循环 }if(now == n){printf("%.2f\n",ans);}else{printf("The maximum travel distance = %.2f\n",st[now].dis+MAX);} }}return 0; 
} 

第八章 递归与分治

8.1 递归策略

8.1.1 n的阶乘

题目链接

#include <iostream>
#include <cstdio>using namespace std;long long Factorial(int n){if(n==0){return 1;}else{return n*Factorial(n-1);}
}
int main(){int n;while(scanf("%d",&n)!=EOF){printf("%lld\n",Factorial(n));}return 0;
}

8.1.2 汉诺塔

基础汉诺塔采用递归实现,实则考试时可以直接推出公式,无需采用递归,f(n)=2^n-1

#include <iostream>
#include <cstdio>using namespace std;long long Hanoi(int n){if(n==1){return 1;}else{return 2*Hanoi(n-1)+1;}
}int main(){int n;while(scanf("%d",&n)!=EOF){printf("%lld\n",Hanoi(n));}return 0;
}

杭电oj -2064
汉诺塔③

//递归方式或者推导公式3^n-1
#include <iostream>
#include <cstdio>using namespace std;long long Hanoi(int n){if(n==1){return 2;}else{return 3*Hanoi(n-1)+2;}
}int main(){int n;while(scanf("%d",&n)!=EOF){printf("%lld\n",Hanoi(n));}return 0;
}

习题 8.1 杨辉三角形 略

习题 8.2 全排列(北京大学复试上机题) (Ex:全排列函数 + auto)

题目链接

//我的代码,菜鸡代码
#include <iostream>
#include <set>
#include <string>
#include <algorithm>using namespace  std;char mystr[30];int n;//字母的数量set <char> sc;void print(){for(int i=0;i<n;i++){printf("%c",mystr[i]);}printf("\n");
}
void dealChar(int t){//决定下标为t的字符是哪一个if(t==n){print();}for(auto it=sc.begin();it!=sc.end();it++){char c=*it;mystr[t]=c;sc.erase(c);dealChar(t+1);sc.insert(c);}
}int main(){string str;cin>>str;n=str.size();for(int i=0;i<n;i++){sc.insert(str[i]);}dealChar(0);return 0;
}

大佬的代码
法一:利用next_permutation(s.begin(), s.end())函数法

//递归——全排列,调用
#include <iostream>
#include <algorithm>
#include <string>using namespace std;int main()
{string str;cin >> str;sort(str.begin(),str.end());cout<<str<<endl;while (next_permutation(str.begin(), str.end()))cout << str << endl;return 0;
}

方法二:利用递归的办法

#include<iostream>
#include<vector>
#include<algorithm>using namespace std;void backtrace(vector<string>& ans, string s, int start, int len){if(start == len){ans.push_back(s);return;}for(int i = start; i < len; i ++){swap(s[i], s[start]);backtrace(ans, s, start + 1, len);}
}
int main(){string s;while(cin >> s){vector<string> ans;backtrace(ans, s, 0, s.size());sort(ans.begin(), ans.end());for(string c : ans)cout << c << endl;}return 0;
}

小结:

  1. STL:set集合,存入会自动进行排序,insert添加元素,erase删除元素
  2. auto的原理就是根据后面的值,来自己推测前面的类型是什么。auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。
std::vector<std::string> ve;
std::vector<std::string>::iterator it = ve.begin();
//可以替换为auto
auto it = ve.begin();
  1. next_premutation()函数详细:https://blog.csdn.net/ACdreamers/article/details/8544505
  1. ext_permutation的函数声明:#include
    bool next_permutation( iterator start, iterator end);
    next_permutation函数的返回值是布尔类型,在STL中还有perv_permutation()函数,排序方式见上面代码。注意先输出一次str
  1. next_permutation()函数功能是输出所有比当前排列大的排列,顺序是从小到大。而prev_permutation()函数功能是输出所有比当前排列小的排列,顺序是从大到小。

8.2 分治法

分而治之
分治法
分治法和贪心区别

8.2.1 Fibonacci

题目链接
方法选择
方法

分治法

#include <iostream>
#include <cstdio>using namespace std;int Fibonacci(int n){if(n==1||n==0){//递归出口return n;}else{return Fibonacci(n-1)+Fibonacci(n-2);}
}
int main(){int n;while(scanf("%d",&n)!=EOF){printf("%d\n",Fibonacci(n));}return 0;
}

递推法

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=30+10;int fibonacci[MAXN];void Initial(){fibonacci[0]=0;fibonacci[1]=1;for(int i=2;i<MAXN;i++){fibonacci[i]=fibonacci[i-1]+fibonacci[i-2];}
}
int main(){int n;Initial();while(scanf("%d",&n)!=EOF){printf("%d\n",fibonacci[n]);}return 0;
}

矩阵快速幂

原理

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=100;//用二维数组模拟矩阵
//矩阵定义
struct Matrix{int row,col;int matrix[MAXN][MAXN];Matrix(){}Matrix(int r,int c):row(r),col(c){}
};//矩阵相乘
Matrix Multiply(Matrix x,Matrix y){Matrix answer=Matrix(x.row,y.col);for(int i=0;i<answer.row;i++){for(int j=0;j<answer.col;j++){answer.matrix[i][j]=0;for(int k=0;k<x.col;k++){answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];}}}return answer;
}//矩阵求幂,采用快速幂运算
Matrix QuickPower(Matrix x,int n){Matrix answer=Matrix(x.row,x.col);for(int i=0;i<x.row;i++){for(int j=0;j<x.col;j++){if(i==j){answer.matrix[i][j]=1;}else{answer.matrix[i][j]=0;}}}while(n!=0){if(n%2==1){answer=Multiply(answer,x);}n/=2;x=Multiply(x,x);}return answer;
}int main(){int n;while(scanf("%d",&n)!=EOF){Matrix fibonacci=Matrix(2,2);fibonacci.matrix[0][0]=1;fibonacci.matrix[0][1]=1;fibonacci.matrix[1][0]=1;fibonacci.matrix[1][1]=0;Matrix answer=QuickPower(fibonacci,n);printf("%d",answer.matrix[0][1]);}return 0;
}

8.2.2 二叉树

题目链接
递归

#include <iostream>
#include <cstdio>int CountNodes(int m,int n){if(m>n){return 0;}else{return CountNodes(2*m, n)+CountNodes(2*m+1,n)+1;}
}
int main(){int m,n;while(scanf("%d%d",&m,&n)!=EOF){if(m==0&&n==0){break;}printf("%d\n",CountNodes(m, n));}return 0;
}

习题 8.3 2的幂次方 (上海交通大学复试上机题)

题目链接

#include <iostream>
#include <string>using namespace std;void pre(int n){if(n==2||n==0){//递归出口printf("%d",n);return;}int ex=31;while(n){if(n&(0x80000000)){//获取当前最高位if(ex==1){//2^1单独输出2printf("2");}else{printf("2(");pre(ex);printf(")");}if((n<<1)!=0){//不是最后一个有效位,就输出加号printf("+");}}ex--;n<<=1;}
}
int main(){int n;scanf("%d",&n);pre(n);return 0;
}

第九章 搜索

搜索:
在这里插入图片描述

eg1: 寻找从A到E的路径:
在这里插入图片描述>状态空间:所有的点
状态转移:转向邻接点
起始状态:A
目标状态:E

eg2:寻找从A到E的最低代价的路径(path from A to E with lowest cost)
状态空间(点,花费)
状态转移:转向邻接点并增加花费
起始状态:(A,0)
目标状态:(E,lowest)

搜索:起始状态经过一系列状态转换达到目标状态的过程。

在这里插入图片描述

计算机中常常采取搜索树解决(Search Trees)

如上述图的搜索树如下:
在这里插入图片描述
在这里插入图片描述

搜索路径的搜索树如上。

在这里插入图片描述
考虑代价的搜索树如上。

搜索策略:
在这里插入图片描述

9.1 BFS

宽度优先搜索(BFS):处理最浅的节点(逐层处理每一层的节点)
在这里插入图片描述

例题 9.1.1 Catch That Cow

poj - 3278
题目链接

分析:
状态空间:(位置n,时间t)
状态转移:(n-1,t+1),(n+1,t+1),(n*2,t+1)
起始状态:(N,0)
目标状态:(K,lowest time)

搜索树:
在这里插入图片描述
应该采用宽度优先搜索,应该一层一层进行搜索,应该在每一层查看是否有状态满足目标状态,因为每一层的借点的时间是相同的。此外,如果存在坐标点已经访问过了,那么没有必要再次浪费时间进行搜索,可以建立visit数组进行标记。

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>using namespace std;const int MAXN=1e5+10;struct Status{int position;int time;Status(){}Status(int p,int t):position(p),time(t){}
};bool visit[MAXN];int BFS(int n,int k){queue<Status> myQueue;myQueue.push(Status(n,0));visit[n]=true;while(!myQueue.empty()){Status current=myQueue.front();if(current.position==k){return current.time;}myQueue.pop();for(int i=0;i<3;i++){Status next=current;if(i==0){next.position-=1;}else if(i==1){next.position+=1;}else{next.position*=2;}next.time++;if(next.position<0||next.position>1e5||visit[next.position]){//如果位置非法,或者已经访问过(没有必要浪费时间再访问),不处理即可continue;}myQueue.push(next);visit[next.position]=true;}}return 0;
}
int main(){int n,k;scanf("%d%d",&n,&k);memset(visit,false,sizeof(visit));printf("%d\n",BFS(n,k));return 0;
}

例题 9.1.2 Find The Multiple

poj - 1426
题目链接

分析:
在这里插入图片描述
但是n*k范围很大,很难搜索。

换思路:从结果出发
在这里插入图片描述
搜索树:
在这里插入图片描述

//Tip c++ 提交会超时。。。。g++不会
#include <iostream>
#include <cstdio>
#include <queue>using namespace std;//bool visit[MAXN]; 由于状态不会重复,因此不需要采用访问数组去重void BFS(int n){queue<long long> myQueue;myQueue.push(1);while(!myQueue.empty()){long long current=myQueue.front();myQueue.pop();if(current%n==0){printf("%lld\n",current);return;}myQueue.push(current*10);myQueue.push(current*10+1);}
}
int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}BFS(n);}return 0;
}

小结

宽度优先搜索总结如下

1.状态:需要确定所求解问题中的状态,通过状态的扩展,遍历所有的状态,从中寻找需要的答案
2.状态扩展方式:在宽度优先搜索中,需要尽可能地扩展状态,并对先扩展的状态得到的状态,先进行下一次状态扩展。
3.有效状态。对于有些状态,并不需要再次扩展它,而是直接舍弃它。因为根据问题的分析可知,目标状态不可能由这些状态经过若干次扩展得到,所以直接舍弃。
4.队列。为了使得先得出的状态能够先扩展,于是使用队列,将得到的状态依次放入队尾,每次取对头元素进行扩展
5.标记。为了判断哪些状态是有效的,哪些状态是无效的,往往使用标记
6.有效状态数。问题中的有效状态数与算法的时间复杂度同数量级,所以在进行搜索之前,必须估算其是否在能够接受范围之内
7.最优。宽度优先搜索常常用于求解最优值问题。因为其搜索到的状态总是按照某个关键字递增,这个特性非常适合求解最优值问题。因此,一旦问题出现最少、最短、最优等关键字,就要考虑是否是宽度优先搜索问题。

习题 9.1 玛雅人的密码(清华大学复试上机题)

题目链接

//我的脑残代码,超时了,用了一个set记录已经访问的string,还以为能够减少复杂度,结果反其道而行之超时了。
#include <iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <set>using namespace std;struct passw{string str;int time;passw(){};passw(string s,int n):str(s),time(n){};
};
bool bfs(string str){queue <passw> qs;qs.push(passw(str,0));set <string> ss;while(!qs.empty()){passw ps=qs.front();string s=ps.str;if(ss.find(s)!=ss.end()){continue;//找过了,不用处理了}if(s.find("2012")!=string::npos){//符合printf("%d",ps.time);return true;}else{ss.insert(ps.str);}qs.pop();for(int i=0;i<s.size()-1;i++){string s1=s;char c=s1[i];s1[i]=s1[i+1];s1[i+1]=c;int time=ps.time+1;qs.push(passw(s1,time));}}    return false;
}
int main(){int N;scanf("%d",&N);string str;while(cin>>str){if(bfs(str)){}else{printf("-1\n");}}return 0;
}
//AC代码
#include <iostream>
#include <cstdio>
#include <string>
#include <queue>using namespace std;struct passw{string str;int time;passw(){};passw(string s,int n):str(s),time(n){};
};
bool bfs(string str){queue <passw> qs;qs.push(passw(str,0));while(!qs.empty()){passw ps=qs.front();if(ps.str.find("2012")!=string::npos){//符合printf("%d",ps.time);return true;}qs.pop();for(int i=0;i<ps.str.size()-1;i++){string s1=ps.str;char c=s1[i];s1[i]=s1[i+1];s1[i+1]=c;qs.push(passw(s1,ps.time+1));}}    return false;
}
int main(){int N;scanf("%d",&N);string str;while(cin>>str){if(bfs(str)){}else{printf("-1\n");}}return 0;
}
//大佬代码,采用unorder_map进行优化
#include<iostream>
#include<queue>
#include<string>
#include<unordered_map>using namespace std;struct NewStr{string s;int step;NewStr(int i, string s):step(i), s(s){}
};unordered_map<string, bool> isVisited;//避免重复入队相同字符串
void bfs(string s){queue<NewStr> q;q.push(NewStr(0, s));isVisited[s] = true;while(!q.empty()){NewStr t = q.front();q.pop();string ts = t.s;if(ts.find("2012") != string::npos){cout << t.step << endl;return;}for(int i = 0; i < ts.size() - 1; i ++){swap(ts[i], ts[i + 1]);if(!isVisited[ts]) {q.push(NewStr(t.step + 1, ts));isVisited[ts] = true;}swap(ts[i], ts[i + 1]);}}cout << -1 << endl;
} int main(){int n;string s;while(cin>>n>>s){bfs(s);}return 0;
}

Tip

1.swap()交换,在algorithm文件中,可以用于交换。
2.unordered_map: 链接说明,不会对数据进行排序的map。
在这里插入图片描述

9.2 DFS(深度优先遍历)

在这里插入图片描述

例题 9.3 A Knight’s Journey

poj - 2488题
题目链接

状态分析在这里插入图片描述
搜索树
在这里插入图片描述
选择深度优先搜索策略。

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>using namespace std;int direction[8][2] = {{-1,-2},{1,-2},{-2,-1},{2,-1},{-2,1},{2,1},{-1,2},{1,2}
};const int MAXN=30;bool visit[MAXN][MAXN];bool DFS(int x,int y,int step,string answer,int p,int q){if(step==p*q){cout<<answer<<endl<<endl;return true;}for(int i=0;i<8;i++){int nx=x+direction[i][0];int ny=y+direction[i][1];if(nx<0||nx>=p||ny<0||ny>=q||visit[nx][ny]){continue;//如果坐标不合法,或者访问过了,则不进行处理}visit[nx][ny]=true;char col=ny+'A';char row=nx+'1';if(DFS(nx,ny,step+1,answer+col+row,p,q)){return true;}visit[nx][ny]=false;}return false;
}int main(){int n;scanf("%d",&n);int caseNumber=0;while(n--){int p,q;scanf("%d%d",&p,&q);memset(visit,false,sizeof(visit));cout<<"Scenario #"<<++caseNumber<<":"<<endl;visit[0][0]=true;if(DFS(0,0,1,"A1",p,q)){continue;}else{printf("impossible\n\n");}}return 0;
}

例题 9.4 Square

poj - 2362

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>using namespace std;const int MAXN=25;int stricks[MAXN];
bool visit[MAXN];bool DFS(int sum,int number,int side,int m){if(number==4){return true;}for(int i=0;i<m;i++){if(visit[i]||sum+sticks[i]>side){continue;}visit[i]=true;if(sum+sticks[i]==side){if(DFS(0,number+1,side,m)){return true;}}else{if(DFS(sum+sticks[i],number,side,m)){return true;}}visit[i]=false;}return false;
}int main(){int n;scanf("%d",&n);while(n--){int m;scanf("%d",&m);int length=0;for(int i=0;i<m;i++){scanf("%d",&sticks[i]);length+=sticks[i];}int side=length/4;memeset(visit,false,sizeof(visit));if(DFS(0,0,side,m)){printf("yes\n");}else{printf("no\n");}}
}

但是会超时,考虑减枝

在这里插入图片描述
在这里插入图片描述
这里拼凑出三个木棍就可以,因为剩下的一根木棍必定可以拼凑出。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>using namespace std;const int MAXN=25;int sticks[MAXN];
bool visit[MAXN];bool DFS(int sum,int number,int position,int side,int m){//剪枝4:position记录上次找的位置if(number==3){//这里找到3根即可返回return true;}int sample=0;for(int i=position;i<m;i++){//剪枝4:从position开始找起if(visit[i]||sum+sticks[i]>side   ||sticks[i]==sample){//剪枝3:如果这根木棍长度与之前那个相同,则不用找了,失败的continue;}visit[i]=true;if(sum+sticks[i]==side){if(DFS(0,number+1,0,side,m)){return true;}else{sample=sticks[i];//剪枝3:找不到,记录长度,后面就不用再找了}}else{if(DFS(sum+sticks[i],number,i+1,side,m)){return true;}else{sample=sticks[i];//剪枝3:同上}}visit[i]=false;}return false;
}bool Compare(int x,int y){return x>y;
}int main(){int n;scanf("%d",&n);while(n--){int m;scanf("%d",&m);int length=0;for(int i=0;i<m;i++){scanf("%d",&sticks[i]);length+=sticks[i];}if(length%4!=0){//剪枝1:如果总长度不能整除4,失败printf("no\n");continue;}int side=length/4;memset(visit,false,sizeof(visit));sort(sticks,sticks+m,Compare);//剪枝2:从大到小排序if(sticks[0]>side){//剪枝2:如果最大的木棍长度超出边长,直接返回失败printf("no\n");continue;}if(DFS(0,0,0,side,m)){printf("yes\n");}else{printf("no\n");}}
}

习题 9.2.1 八皇后

题目链接

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>using namespace std;vector<int> vs;int arr[10];bool Judge(int index,int data){for(int i=1;i<index;i++){if(arr[i]==data||(i-arr[i]==index-data)||(i+arr[i]==index+data)){return false;}}return true;      
}
void dfs(int k,int n){//第k行if(k==9){vs.push_back(n);return;}for(int i=1;i<=8;i++){if(Judge(k,i)){arr[k]=i;dfs(k+1,n*10+i);}}
}
int main(){dfs(1,0);sort(vs.begin(),vs.end());int n;while(scanf("%d",&n)!=EOF){printf("%d\n",vs[n-1]);}return 0;
}

第十章 数据结构二

在这里插入图片描述

10.1 二叉树

在这里插入图片描述
结点
在这里插入图片描述

二叉树遍历方式
在这里插入图片描述

10.1.1 例10.1 二叉树遍历(清华大学复试上机题)

本题主要考察的知识点是二叉树的建立和二叉树的中序遍历。因此,本题只要递归地建立一棵二叉树即可,再递归的进行中序遍历
此外,注意Build函数中position参数类型是整形引用&。
题目链接

#include <iostream>
#include <cstdio>
#include <string>using namespace std;struct TreeNode{char data;TreeNode *leftChild;TreeNode *rightChild;TreeNode(char c):data(c),leftChild(nullptr),rightChild(nullptr){}
};TreeNode *Build(int &position,string str){char c=str[position++];if(c=='#'){return nullptr;}TreeNode *root=new TreeNode(c);root->leftChild=Build(position,str);root->rightChild=Build(position,str);return root;
}void InOrder(TreeNode *root){if(root==nullptr){return;}InOrder(root->leftChild);printf("%c ",root->data);InOrder(root->rightChild);return;
}int main(){string str;while(cin>>str){int position=0;TreeNode *root=Build(position,str);InOrder(root);printf("\n");}return 0;
}

10.1.2 例10.2 二叉树遍历(华中科技大学复试上机题)

题目链接

前序序列中序序列唯一建立一棵二叉树代码

#include <iostream>
#include <cstdio>
#include <string>using namespace std;struct TreeNode{char data;TreeNode *leftChild,*rightChild;TreeNode(char c):data(c),leftChild(nullptr),rightChild(nullptr){};//建议用nullptr,防止二义性
};TreeNode* Build(string preOrder,string inOrder){if(preOrder.size()==0){return nullptr;}char c=preOrder[0];TreeNode *root=new TreeNode(c);int position=inOrder.find(c);root->leftChild=Build(preOrder.substr(1,position), inOrder.substr(0,position));root->rightChild=Build(preOrder.substr(position+1), inOrder.substr(position+1));return root;                     
}void PostOrder(TreeNode *root){if(root==nullptr){return ;}PostOrder(root->leftChild);PostOrder(root->rightChild);printf("%c",root->data);
}int main(){string preOrder,inOrder;while(cin>>preOrder>>inOrder){TreeNode *root=Build(preOrder,inOrder);PostOrder(root);printf("\n");}return 0;
}

10.2 二叉排序树

例题10.3 二叉排序树(华中科技大学复试上机题)

题目链接

#include <iostream>
#include <cstdio>using namespace std;struct TreeNode{int data;TreeNode *leftChild;TreeNode *rightChild;TreeNode(int x):data(x),leftChild(nullptr),rightChild(nullptr){}
};TreeNode *Insert(TreeNode *root,int x,int father){if(root==nullptr){root = new TreeNode(x);printf("%d\n",father);}else if(x < root->data){root->leftChild=Insert(root->leftChild,x,root->data);}else if(root->data<x){root->rightChild=Insert(root->rightChild,x,root->data);}return root;
}int main(){int N;while(scanf("%d",&N)!=EOF){TreeNode* root=nullptr;while(N--){int x;scanf("%d",&x);root=Insert(root,x,-1);}}return 0;
}

例题10.4 二叉排序树(华中科技大学复试上机题)

题目链接

#include <iostream>
#include <cstdio>using namespace std;struct TreeNode{int data;TreeNode *leftChild;TreeNode *rightChild;TreeNode(int x):data(x),leftChild(nullptr),rightChild(nullptr){}
};void PreOrder(TreeNode *root){if(root==nullptr){return;}printf("%d ",root->data);PreOrder(root->leftChild);PreOrder(root->rightChild);return;
}void InOrder(TreeNode *root){if(root==nullptr){return;}InOrder(root->leftChild);printf("%d ",root->data);InOrder(root->rightChild);return;
}void PostOrder(TreeNode *root){if(root==nullptr){return;}PostOrder(root->leftChild);PostOrder(root->rightChild);printf("%d ",root->data);return;
}TreeNode *Insert(TreeNode *root,int x){if(root==nullptr){root = new TreeNode(x);}else if(x < root->data){root->leftChild=Insert(root->leftChild,x);}else if(root->data<x){root->rightChild=Insert(root->rightChild,x);}return root;
}int main(){int n;while(scanf("%d",&n)!=EOF){TreeNode* root=nullptr;while(n--){int x;scanf("%d",&x);root=Insert(root,x);}PreOrder(root);printf("\n");InOrder(root);printf("\n");PostOrder(root);printf("\n");}return 0;
}

习题 10.1 二叉搜索树

题目链接

递归建立二叉搜索树代码记忆!!

#include <iostream>
#include <cstdio>using namespace std;
struct TreeNode{int data;TreeNode *leftChild,*rightChild;TreeNode(int n):data(n),leftChild(nullptr),rightChild(nullptr){};
};TreeNode *Insert(TreeNode *root,int n){if(root==nullptr){root=new TreeNode(n);}else if(root->data<n){root->rightChild=Insert(root->rightChild,n);}else if(root->data>n){root->leftChild=Insert(root->leftChild,n);}return root;
}bool same(TreeNode *root1,TreeNode *root2){if(root1==nullptr&&root2==nullptr){return true;}if(root1->data==root2->data&&same(root1->leftChild,root2->leftChild)&&same(root1->rightChild,root2->rightChild)){return true;}return false;
}
int main(){string str;int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}string str;cin>>str;TreeNode *root=nullptr;for(int i=0;i<str.length();i++){root=Insert(root,str[i]-'0');}while(n--){cin>>str;TreeNode *root1=nullptr;for(int i=0;i<str.length();i++){root1=Insert(root1,str[i]-'0');}if(same(root,root1)){printf("YES\n");}else{printf("NO\n");}}}return 0;
}

10.3 优先队列

在这里插入图片描述

优先队列实现原理
在这里插入图片描述
复杂度:查询O(1) ,入队O(logn),出队O(logn)
在这里插入图片描述

priority_queue
在这里插入图片描述

priority_quque使用

 #include <cstdio>
#include <queue>using namespace std;priority_queue<int> myPriorityQueue;int main(){int arr[10]={3,2,4,1,5,6,9,0,8,7};for(int i=0;i<10;i++){myPriorityQueue.push(arr[i]);}int sum=0;while(!myPriorityQueue.empty()){printf("%d ",myPriorityQueue.top());//注意这里是top()。队列是frontsum+=myPriorityQueue.top();myPriorityQueue.pop();}
}

优先队列作用
在这里插入图片描述

例题10.5 复数集合

题目链接

#include <cstdio>
#include <queue>
#include <iostream>
#include <string>using namespace std;struct Complex{int real;int imag;Complex(int a,int b):real(a),imag(b){}bool operator < (Complex c) const{if(real *real + imag*imag == c.real * c.real + c.imag * c.imag){//注意这里实现 比较,比较模长可以通过平方比较return imag > c.imag;}return real *real + imag*imag < c.real * c.real + c.imag * c.imag;}
};int main(){int n;while(scanf("%d",&n)!=EOF){priority_queue<Complex> myPriorityQueue;while(n--){string str;cin>>str;if(str=="Pop"){if(myPriorityQueue.empty()){printf("empty\n");}else{Complex current=myPriorityQueue.top();//注意这里是topmyPriorityQueue.pop();printf("%d+i%d\n",current.real,current.imag);printf("SIZE = %d\n",myPriorityQueue.size());}}else{int a,b;scanf("%d+i%d",&a,&b);myPriorityQueue.push(Complex(a,b));printf("SIZE = %d\n",myPriorityQueue.size());}}}return 0;
}

例题10.6 哈夫曼树

在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <queue>using namespace std;int main(){int n;while(scanf("%d",&n)!=EOF){priority_queue<int,vector<int>,greater<int> > myPriorityQueue;while(n--){int x;scanf("%d",&x);myPriorityQueue.push(x);}int answer=0;while(myPriorityQueue.size()>1){int a=myPriorityQueue.top();myPriorityQueue.pop();int b=myPriorityQueue.top();myPriorityQueue.pop();answer+=(a+b);myPriorityQueue.push(a+b);}printf("%d",answer);}return 0;
}

习题 10.3 查找第K小的数(北京邮电大学复试上机题)

题目链接

TIP

1.注意priority_queue默认为大顶堆,如果想要创建小顶堆,可以

priority_queue <int,vector,greater > pq; 注意两个 > >中间要写一个空格。

#include <iostream>
#include <queue>
#include <algorithm>using namespace std;int main(){int n;scanf("%d",&n);priority_queue <int,vector<int>,greater<int> > pq;for(int i=0;i<n;i++){int num;scanf("%d",&num);pq.push(num);}int k;scanf("%d",&k);int cnt;int previous;if(k==0){printf("%d",pq.top());return 0;}while(k--){if(previous==pq.top()){k++;}previous=pq.top();pq.pop();}printf("%d",previous);return 0;
}

习题 10.3 搬水果(吉林大学复试上机题)

题目链接

#include <iostream>
#include <queue>
#include <cstdio>using namespace std;int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}priority_queue <int,vector<int>,greater<int> > q;int answer=0;for(int i=0;i<n;i++){int weight;scanf("%d",&weight);q.push(weight);}while(q.size()>=2){int one=q.top();q.pop();int two=q.top();q.pop();answer+=(one+two);q.push(one+two);}printf("%d\n",answer);}return 0;
}

10.4 散列表(map,unordered_map)

散列表思想
在这里插入图片描述

C++提供的映射及时间复杂度
在这里插入图片描述

map容器
使用例子:

#include <cstdio>
#include <iostream>
#include <map>using namespace std;map <string,int> myMap;//内部按照关键字进行排序,底层为红黑树int main(){//插入,添加元素myMap["Emma"]=67;myMap.insert(pair<string,int>("Bob",72));//查cout<<myMap["Emma"]<<endl;cout<<myMap.at("Bob")<<endl;//删除myMap.erase("Emma");map<string,int>::iterator it;for(it=myMap.begin();it!=myMap.end();it++){cout << it->first <<" "<<it->second<<endl;}//查找it=myMap.find("Bob");//返回迭代器if(it!=myMap.end()){return 0;//未找到}cout<<myMap.size();myMap.clear();//晴空}

10.4.1 例题10.7 查找学生信息

在这里插入图片描述

#include <cstdio>
#include <iostream>
#include <map>using namespace std;map <string,string> student;int main(){int n;scanf("%d",&n);getchar();//这里吃掉回车符while(n--){string str;getline(cin,str);int position=str.find(" ");string key=str.substr(0,position);student[key]=str;}int m;scanf("%d",&m);while(m--){string key;cin>>key;map<string,string>::iterator it=student.find(key);if(it!=student.end()){cout<<it->second<<endl;}else{cout<<"No Answer!"<<endl;}
或者可以采用下面的方式判断
//         string answer=student[key];
//         if(answer==""){
//             answer="No Answer";
//         }
//         cout<<answer<<endl;}return 0;
}

10.4.2 例题10.8 魔咒词典(浙江大学复试上机题)

题目链接

#include <iostream>
#include <cstdio>
#include <string>
#include <map>using namespace std;map<string,string> dictionary;int main(){string str;while(getline(cin,str)){if(str=="@END@"){break;}int pos=str.find("]");string key=str.substr(0,pos+1);string value=str.substr(pos+2);dictionary[key]=value;dictionary[value]=key;}int n;scanf("%d",&n);getchar();while(n--){string key;getline(cin,key);string answer=dictionary[key];if(answer==""){answer="what?";}else if(answer[0]=='['){answer=answer.substr(1,answer.size()-2);}cout<<answer<<endl;}return 0;
}

10.4.3 例题10.8 子串计算(北京大学复试上机题)

题目链接

迭代器it,访问元素,it->first,it->second

#include <iostream>
#include <cstdio>
#include <string>
#include <map>using namespace std;int main(){string str;while(cin>>str){map<string,int> number;for(int i=0;i<=str.size();i++){//i表示子串结束位置下标for(int j=0;j<i;j++){//j表示子串起始位置string key=str.substr(j,i-j);//每个子串number[key]++;//映射值加一}}map<string,int>::iterator it;//定义迭代器for(it=number.begin();it!=number.end();it++){if(1<it->second){cout<<it->first<<" "<<it->second<<endl;}}}return 0;
}

10.4.4 习题 10.4 统计同成绩学生人数(浙江大学复试上机题)

题目链接

#include <iostream>
#include <cstdio>
#include <map>using namespace std;int main(){int N;while(scanf("%d",&N)!=EOF){if(N==0){break;}map<int,int> mp;int score;for(int i=0;i<N;i++){scanf("%d",&score);mp[score]++;}scanf("%d",&score);printf("%d\n",mp[score]);}return 0;
}

10.4.5 习题 10.5 开门人和关门人(浙江大学复试上机题)

题目链接

//用排序写的
#include <iostream>
#include <cstdio>
#include <queue>
#include <string>
#include <algorithm>using namespace std;struct info{string num;string time1;string time2;
};
const int maxn=10000+5;
info arr[maxn];
bool cmp1(info info1,info info2){return info1.time1<info2.time1;
}
bool cmp2(info info1,info info2){return info1.time2>info2.time2;
}
int main(){int M;scanf("%d",&M);for(int i=0;i<M;i++){cin>>arr[i].num>>arr[i].time1>>arr[i].time2;}sort(arr,arr+M,cmp1);cout<<arr[0].num<<" ";sort(arr,arr+M,cmp2);cout<<arr[0].num;return 0;
}

10.4.6 习题 10.6 谁是你的潜在朋友(北京大学复试上机题)

题目链接

#include <iostream>
#include <cstdio>
#include <map>using namespace std;const int  MAXN=10000+5;
int arr[MAXN];
int main(){int N,M;scanf("%d %d",&N,&M);map<int,int>booklike;for(int i=0;i<N;i++){scanf("%d",&arr[i]);booklike[arr[i]]++;}for(int i=0;i<N;i++){if(booklike[arr[i]]==1){printf("BeiJu\n");}else{printf("%d\n",booklike[arr[i]]-1);}}return 0;
}

第十一章 图论问题

体系:
在这里插入图片描述

11.1 概述

定义
在这里插入图片描述
分类
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

存储方式
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
使用例子

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;const int MAXN=1000;int graph[MAXN][MAXN];//邻接矩阵存储图vector<int> graph1[MAXN];//邻接表表示图,向量表示顶点表

11.2 并查集

集合概念
在这里插入图片描述
并查集表示
在这里插入图片描述
并查集操作
在这里插入图片描述

查询Find,返回根节点即可,判断根结点是否相等就可以判断是否属于同一个集合
在这里插入图片描述
合并:将一棵树作为另外一棵树的子树即可
在这里插入图片描述

并查集简单实现

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=1000;int father[MAXN];void Initial(int n){for(int i=0;i<n;i++){father[i]=i;//初始化每个结点只有自己}return;
}int Find(int x){if(x!=father[x]){return Find(father[x]);}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(x);if(x!=y){father[y]=x;}
}int main(){return 0;
}

但是并查集查询效率取决与树高,而上述代码未进行优化,因此要进行路径压缩,矮树合并到高树。
在这里插入图片描述在这里插入图片描述

优化并查集

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=1000;int father[MAXN];
int height[MAXN];//用于矮树合并到高树上void Initial(int n){for(int i=0;i<n;i++){father[i]=i;//初始化每个结点只有自己height[i]=0;}return;
}int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);//查找过程中将所有子孙节点直接挂接到根上}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){//矮树合并到高树上father[x]=y;}else if(height[x]>height[y]){father[y]=x;}else{father[y]=x;height[x]++;//注意这里更新树高}}
}int main(){return 0;
}

11.2.1 例题11.2 连通图

题目链接在
说明
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=1000+50;int father[MAXN];
int height[MAXN];//用于矮树合并到高树上void Initial(int n){for(int i=0;i<=n;i++){father[i]=i;//初始化每个结点只有自己height[i]=0;}return;
}int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);//查找过程中将所有子孙节点直接挂接到根上}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){//矮树合并到高树上father[x]=y;}else if(height[x]>height[y]){father[y]=x;}else{father[y]=x;height[x]++;//注意这里更新树高}}
}int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0){break;}Initial(n);//初始化!!while(m--){int x,y;scanf("%d%d",&x,&y);Union(x,y);}int component=0;for(int i=1;i<=n;i++){if(i==Find(i)){component++;}}if(component==1){printf("YES\n");}else{printf("NO\n");}}return 0;
}

11.2.2 例题11.1 畅通工程(浙江大学上机题)

Tip!!!
注意并查集的FInd函数的书写,尤其是递归操作!!!!!!
对于每一个输入案例,别忘了Initial函数!!!!

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=1000+5;int father[MAXN];
int height[MAXN];void Initial(){for(int i=0;i<MAXN;i++){father[i]=i;height[i]=1;}return;
}
int Find(int x){//注意这里代码书写,容易写错!!if(x!=father[x]){father[x]=Find(father[x]);}return father[x];
}
void Union(int x,int y){x=Find(x);y=Find(y);if(x==y){return;}if(height[x]<height[y]){father[y]=x;}else if(height[y]>height[x]){father[x]=y;}else{father[x]=y;height[y]++;}return;
}int main(){int N,M;while(scanf("%d",&N)!=EOF){if(N==0){break;}Initial();//注意这里每次测试用例都要Initial!!!!!scanf("%d",&M);for(int i=0;i<M;i++){int x,y;scanf("%d%d",&x,&y);Union(x,y);}int answer=-1;for(int i=1;i<=N;i++){if(i==Find(i)){answer++;}}printf("%d\n",answer);}return 0;
}

11.2.3 例题11.3 Is It A Tree(北京大学上机题)

题目链接

#include <iostream>
#include <cstdio>using namespace std;const int MAXN=10000;int father[MAXN];//父亲结点
int height[MAXN];//结点高度
int inDegree[MAXN];//入度
bool visit[MAXN];//标记void Initial(){//初始化for(int i=0;i<MAXN;i++){father[i]=i;height[i]=0;inDegree[i]=0;visit[i]=false;}
}int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){father[x]=y;}else if(height[y]<height[x]){father[y]=x;}else{father[y]=x;height[x]++;}}return;
}bool isTree(){bool flag=true;int component=0;//连通分量数目int root=0;//根结点数目for(int i=0;i<MAXN;i++){if(!visit[i]){continue;}if(father[i]==i){component++;}if(inDegree[i]==0){root++;}else if(inDegree[i]>1){//入度不满足要求flag=false;        }}if(component!=1||root!=1){//不符合树的定义flag=false;}if(component==0&&root==0){//空集也是树flag=true;}return flag;
}
int main(){int x,y;int caseNumber=0;Initial();while(scanf("%d%d",&x,&y)!=EOF){if(x==-1&&y==-1){break;}if(x==0&&y==0){if(isTree()){printf("Case %d is a tree.\n",++caseNumber);}else{printf("Case %d is not a tree.\n",++caseNumber);}Initial();}else{Union(x,y);inDegree[y]++;visit[x]=true;visit[y]=true;}}return 0;
}

11.2.4 习题11.1 找出直系亲属(浙江大学复试上机题)

题目链接

//大佬代码
#include <iostream>
#include <string>
using namespace std;
const int MAXN = 50;int son[MAXN];      //父节点是儿子,所以以son命名
int height[MAXN];    //表示结点高度,最小的儿子高度为0,越往下辈分越大//并查集思想void Initial(){                //初始化函数  父节点默认设为自己,高度默认为0for(int i=0;i<MAXN;i++){son[i] = i;height[i] = 0;}
}int Find(int x,int y,int count){   if(son[x]==son[y] && x!=y && son[x]!=x && son[y]!=y) return -1;  //若当前两个节点的父节点是同一个,即拥有同个儿子,则不是直系if(height[x]<height[y]){  //高度高的辈分大,则辈分高取自己的儿子,然后递归find,count作为记录取儿子的次数,取一次表面差一个辈分y = son[y];count++;return Find(x,y,count);}else if(height[x]>height[y]){  //同理x = son[x];count++;return Find(x,y,count);}else{return count;   }return -1;
}int main(){int n,m;while(cin >> n >> m){Initial();for(int i=0;i<n;i++){string str;cin >> str;int a = str[0] - 'A';    //由于是A-Z的字符,则用-'A'来变成数,方便记录son数组的值if(str[1]!='-'){  //如果缺失则跳过int b = str[1] - 'A';son[b] = a;       //记录自己的儿子节点height[b] = 1 + height[a];  //b的高度是儿子的高度加1,以此类推,高度越高辈分越大}if(str[2]!='-'){  int c = str[2] - 'A';son[c] = a;height[c] = 1 + height[a];}}for(int i=0;i<m;i++){string str;cin >> str;int a = str[0]-'A';int b = str[1]-'A';//两个判断有点冗余,可以封装成函数作为调用if(height[a]>=height[b]){   //若a高度大于b,则a的辈分高,输出parentint ans = Find(a,b,0);string str1 = "";if(ans==-1){str1 += "-";cout << str1 << endl;}else if(ans==1){str1 += "parent";cout << str1 << endl;}else if(ans==2){str1 += "grandparent";cout << str1 << endl;}else if(ans>2){str1 += "grandparent";while(ans>2){str1 = "great-" + str1;ans--;}cout << str1 << endl;}}else if(height[a]<height[b]){   //若a的高度低,则a的辈分低,输出childint ans = Find(a,b,0);string str1 = "";if(ans==-1){str1 += "-";cout << str1 << endl;}else if(ans==1){str1 += "child";cout << str1 << endl;}else if(ans==2){str1 += "grandchild";cout << str1 << endl;}else if(ans>2){str1 += "grandchild";while(ans>2){str1 = "great-" + str1;ans--;}cout << str1 << endl;}}}   }return 0;
}

11.2.5 习题11.2 第一题(上海交通大学复试上机题)

题目链接

注意本题采用map结构构造并查集,或者开一个大数组

#include <iostream>
#include <cstdio>
#include <map>using namespace std;//用map实现并查集!!
map<int,int> father;
map<int,int> height;
int Find(int x){if(father.find(x)!=father.end()){if(father[x]!=x){//只有比较里面用x,其他都是father[x]father[x]=Find(father[x]);//!!!!!!!!!!!注意这里是Find(father[x])!!!!!!!!}}else{father[x]=x;height[x]=1;}return father[x];
}
void Union(int x,int y){x=Find(x);y=Find(y);if(x==y){return;}if(height[x]>height[y]){father[y]=x;}else if(height[x]<height[x]){father[x]=y;}else{father[x]=y;height[y]++;}
}int main(){int i,j;while(scanf("%d%d",&i,&j)!=EOF){Union(i,j);}int answer=0;for(auto it=father.begin();it!=father.end();it++){if(it->first==it->second){answer++;}}printf("%d\n",answer);return 0;
}

11.2.6 习题11.3 Head of a Gang(浙江大学复试上机题)

太菜了我,大神代码

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#define MAX_N 2000
int parent[MAX_N], r[MAX_N], k[MAX_N], w[MAX_N];
int population = 0;
map<string, int> indexs;
string names[MAX_N * 2];
vector<int> gangs[MAX_N];
int head[MAX_N], cnt = 0;
void init(int N){for(int i = 0; i < MAX_N; i++){parent[i] = i;w[i] = 0;r[i] = 0;k[i] = 0;head[i]=0;gangs[i].clear();}population=0;indexs.clear();cnt=0;}
int find(int p){while (p != parent[p]) {parent[p] = parent[parent[p]]; // 路径压缩p = parent[p];}return p;
}
bool connected(int p, int q){return find(p) == find(q);
}
// union是保留关键字,所以函数名不能为union
void Union(int p, int q, int t){int rootP = find(p), rootQ = find(q);if(rootP == rootQ){k[rootP] += t;return;}// 总是将小树合并到大树上,如果两棵树高度一样,则任意合并,合并后树的高度加1,合并树的同时合并计数if(r[rootP] < r[rootQ]){parent[rootP] = rootQ;k[rootQ] += k[rootP] + t; // 合并并累加k}else if(r[rootP] > r[rootQ]){parent[rootQ] = rootP;k[rootP] += k[rootQ] + t; // 合并并累加k}else{parent[rootQ] = rootP;k[rootP] += k[rootQ] + t; // 合并并累加kr[rootP]++;}
}// 获得下标
int getIndex(string s){if(indexs.find(s) == indexs.end()){indexs[s] = population;names[population] = s;return population++;}return indexs[s];
}
bool cmp(int h1, int h2){return names[h1] < names[h2];
}int main() {int N, K;// 读取输入while(scanf("%d %d", &N, &K)!=EOF){init(N);string s1, s2;for(int i = 0, u, v, t; i < N; i++){cin >> s1 >> s2;scanf("%d", &t);u = getIndex(s1);v = getIndex(s2);Union(u, v, t);w[u] += t;w[v] += t;}// 将每个人加入到自己的组中for(int i = 0; i < population; i++){// 这里不能直接使用parent[i],因为可能存在需要路径压缩gangs[find(i)].push_back(i);}for(int i = 0, size, h; i < population; i++){// 过滤k值和人数不符合的组if(k[i] <= K || (size = (int)gangs[i].size()) <= 2) continue;// 遍历组内成员获得头目h = i;for(int p : gangs[i]){if(w[p] > w[h]){h = p;}}head[cnt++] = h;}// 对头目按字典名排序sort(head, head + cnt, cmp);// 输出结果printf("%d\n", cnt);for(int i = 0, p; i < cnt; i++){p = head[i];// 但是这里又可以直接使用parent[p],因为在前面加入组的时候对每个点都执行了一次find(p),全部被路径压缩printf("%s %d\n", names[head[i]].c_str(), (int)gangs[parent[p]].size());}}return 0;
}

11.3 最小生成树

算法实现
在这里插入图片描述
Kruskal 时间复杂度O(ElogE)
在这里插入图片描述

时间复杂度分析
在这里插入图片描述
一般采用Kruskal算法即可。

11.3.1 例题11.4 还是畅通工程

题目链接

#include <iostream>
#include <cstdio>
#include <algorithm>using namespace std;const int MAXN=100;struct Edge{int from;int to;int length;bool operator <(const Edge& e) const{return length<e.length;}
};Edge edge[MAXN*MAXN];
int father[MAXN];
int height[MAXN];//用于矮树合并到高树上void Initial(int n){for(int i=0;i<=n;i++){father[i]=i;//初始化每个结点只有自己height[i]=0;}return;
}int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);//查找过程中将所有子孙节点直接挂接到根上}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){//矮树合并到高树上father[x]=y;}else if(height[x]>height[y]){father[y]=x;}else{father[y]=x;height[x]++;//注意这里更新树高}}
}int Kruskal(int n,int edgeNumber){Initial(n);sort(edge,edge+edgeNumber);int sum=0;for(int i=0;i<edgeNumber;i++){Edge current=edge[i];if(Find(current.from)!=Find(current.to)){Union(current.from,current.to);sum+=current.length;}}return sum;
}int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}int edgeNumber=n*(n-1)/2;for(int i=0;i<edgeNumber;i++){scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].length);}int answer=Kruskal(n,edgeNumber);printf("%d\n",answer);}return 0;
}

11.3.3 例题11.5 继续畅通工程

题目链接

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>
#include <algorithm>using namespace std;const int MAXN=100;struct Edge{int from;int to;int length;bool operator<(const Edge&e)const{return length<e.length;}
};Edge edge[MAXN*MAXN];
int father[MAXN];
int height[MAXN];void Initial(int n){for(int i=0;i<=n;i++){father[i]=i;height[i]=0;}
}
int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);}return father[x];
}
void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){father[x]=y;}else if(height[x]>height[y]){father[y]=x;}else{father[y]=x;height[x]++;}}return;
}
int Kruskal(int n,int edgeNumber){Initial(n);sort(edge,edge+edgeNumber);int sum=0;for(int i=0;i<edgeNumber;i++){Edge current=edge[i];if(Find(current.from)!=Find(current.to)){Union(current.from,current.to);sum+=current.length;}}return sum;
}
int main(){int n;while(scanf("%d",&n)!=EOF){if(n==0){break;}int edgeNumber=n*(n-1)/2;for(int i=0;i<edgeNumber;i++){int status;scanf("%d%d%d%d",&edge[i].from,&edge[i].to,&edge[i].length,&status);if(status){edge[i].length=0;}}int answer=Kruskal(n, edgeNumber);printf("%d\n",answer);}return 0;
}

11.3.4 习题11.4 Freckles

Tip:
注意类型书写成double,否则会出现结果为0的错误

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>using namespace std;const int MAXN=100;
struct Point{double x;double y;Point(int a,int b):x(a),y(b){};Point(){};
};
struct Edge{int from;int to;double length;bool operator <(const Edge& e) const{return length<e.length;}Edge(int f,int t,double l):from(f),to(t),length(l){};Edge(){};
};Point points[MAXN];
Edge edge[MAXN*MAXN];
int father[MAXN];
int height[MAXN];//用于矮树合并到高树上void Initial(int n){for(int i=0;i<=n;i++){father[i]=i;//初始化每个结点只有自己height[i]=0;}return;
}int Find(int x){if(x!=father[x]){father[x]=Find(father[x]);//查找过程中将所有子孙节点直接挂接到根上}return father[x];
}void Union(int x,int y){x=Find(x);y=Find(y);if(x!=y){if(height[x]<height[y]){//矮树合并到高树上father[x]=y;}else if(height[x]>height[y]){father[y]=x;}else{father[y]=x;height[x]++;//注意这里更新树高}}
}double Kruskal(int n,int edgeNumber){Initial(n);sort(edge,edge+edgeNumber);double sum=0;for(int i=0;i<edgeNumber;i++){Edge current=edge[i];if(Find(current.from)!=Find(current.to)){Union(current.from,current.to);sum+=current.length;}}return sum;
}int main(){int n;while(scanf("%d",&n)!=EOF){int num=0;if(n==0){break;}double x,y;for(int i=0;i<n;i++){scanf("%lf %lf",&x,&y);points[i]=Point(x,y);}int cnt=0;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){Point p1=points[i];Point p2=points[j];double dis=sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));edge[cnt++]=Edge(i,j,dis);}}printf("%.2f",Kruskal(n, cnt));}return 0;
}

11.4 最短路径

Dijkstra Algorithm

11.4.1 畅通工程续

杭电oj-1874题

注意本题邻接表的写法,以及获取元素方法。
Dijstra Algorithm写法

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>using namespace std;const int MAXN=200;
const int INF=INT_MAX;//无穷大或者0x7FFFFFFFstruct Edge{int to;int length;Edge(int t,int l):to(t),length(l){}
};vector <Edge> graph[MAXN];
int dis[MAXN];
bool visit[MAXN];void Dijkstra(int start,int n){memset(visit,false,sizeof(visit));fill(dis,dis+n,INF);dis[start]=0;for(int i=0;i<n;i++){int u=-1;for(int j=0;j<n;j++){if(visit[j]){//已经查找过continue;}if(u==-1||dis[j]<dis[u]){u=j;//更新最小值下标索引}}for(int j=0;j<graph[u].size();j++){int v=graph[u][j].to;int d=graph[u][j].length;if(dis[u]+d<dis[v]){dis[v]=dis[u]+d;}}visit[u]=true;}return;
}int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){memset(graph,0,sizeof(graph));while(m--){int from,to,length;scanf("%d%d%d",&from,&to,&length);graph[from].push_back(Edge(to,length));//注意这里是无向图,对于每一条边邻接表中有两个边表结点需要添加graph[to].push_back(Edge(from,length));}int start;int terminal;scanf("%d%d",&start,&terminal);Dijkstra(start,n);if(dis[terminal]==INF){dis[terminal]=-1;}}return 0;
}

针对于Dijstra算法的优化
采用优先队列选择离原点最近的点在这里插入图片描述

//优化算法如下
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>using namespace std;const int MAXN=200;
const int INF=INT_MAX;//无穷大或者0x7FFFFFFFstruct Edge{int to;int length;Edge(int t,int l):to(t),length(l){}
};struct Point{int number;int distance;Point(int n,int d):number(n),distance(d){}bool operator < (const Point&p) const{return distance > p.distance;}
};vector <Edge> graph[MAXN];
int dis[MAXN];
bool visit[MAXN];void Dijkstra(int start,int n){fill(dis,dis+n,INF);dis[start]=0;//这里进行算法优化,采用优先队列选择下一个点priority_queue<Point> myPriorityQueue;myPriorityQueue.push(Point(start,dis[start]));while(!myPriorityQueue.empty()){int u=myPriorityQueue.top().number;myPriorityQueue.pop();for(int j=0;j<graph[u].size();j++){int v=graph[u][j].to;int d=graph[u][j].length;if(dis[u]+d<dis[v]){dis[v]=dis[u]+d;myPriorityQueue.push(Point(v,dis[v]));}}}return;
}int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){memset(graph,0,sizeof(graph));while(m--){int from,to,length;scanf("%d%d%d",&from,&to,&length);graph[from].push_back(Edge(to,length));//注意这里是无向图,对于每一条边邻接表中有两个边表结点需要添加graph[to].push_back(Edge(from,length));}int start;int terminal;scanf("%d%d",&start,&terminal);Dijkstra(start,n);if(dis[terminal]==INF){dis[terminal]=-1;}}return 0;
}

11.4.2 例题11.7 最短路径问题

题目链接

本题只需添加代价数组,然后在更新距离过程中考虑距离相同时代价也要比较更新即可。

if((dis[v]==dis[u]+l&&cost[v]>cost[u]+p)||dis[v]>dis[u]+l){//注意松弛操作的条件变换dis[v]=dis[u]+l;//注意这里是l,不是1cost[v]=cost[u]+p;myPriorityQueue.push(Point(v,dis[v]));}
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
#include <climits>using namespace std;const int MAXN=1000+5;
const int INF=INT_MAX;//无穷设为很大的数struct Edge{int to;//终点int length;//长度int price;//花费Edge(int t,int l,int p):to(t),length(l),price(p){}
};
struct Point{int number;//点的编号int distance;//原点到该点的距离Point(int n,int d):number(n),distance(d){}bool operator < (const Point&p)const{return distance>p.distance;//距离小的优先级高}
};
vector<Edge> graph[MAXN];//邻接表实现图
int dis[MAXN];//原点到各点距离
int cost[MAXN];//记录花费
void Dijstra(int s){priority_queue <Point> myPriorityQueue;dis[s]=0;cost[s]=0;myPriorityQueue.push(Point(s,dis[s]));while(!myPriorityQueue.empty()){int u=myPriorityQueue.top().number;//离原点最近的点myPriorityQueue.pop();for(int i=0;i<graph[u].size();i++){int v=graph[u][i].to;int l=graph[u][i].length;int p=graph[u][i].price;if((dis[v]==dis[u]+l&&cost[v]>cost[u]+p)||dis[v]>dis[u]+l){//注意松弛操作的条件变换dis[v]=dis[u]+l;//注意这里是l,不是1cost[v]=cost[u]+p;myPriorityQueue.push(Point(v,dis[v]));}}}return;
}
int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0){break;}memset(graph,0,sizeof(graph));//图初始化fill(dis,dis+n+1,INF);//距离初始化为无穷fill(cost,cost+n+1,INF);//花费初始化为无穷while(m--){int from,to,length,price;scanf("%d%d%d%d",&from,&to,&length,&price);graph[from].push_back(Edge(to,length,price));graph[to].push_back(Edge(from,length,price));}int s,t;scanf("%d%d",&s,&t);Dijstra(s);printf("%d %d\n",dis[t],cost[t]);}return 0;
}

11.4.3 习题11.6 最短路径(上海交通大学复试上机题)

题目链接

本题乍一看是单元最短路径问题,这是一道披着最短路径外衣的最小生成树,因为路径长度是从20开始,其实举例到第3条路径就可以发现:22=4>20+21,也就是说,当一条边的两个端点不在同一集合时,这条边的长度就是这两点间的最短距离,可以直接取mod,这时只用更新一下两个集合里各点间的距离就行,而如果这条边的两个端点在同一集合,那么这条边就可以直接舍去了,因为这条边的长度将会比之前出现的所有边长度的总和还要长。
因此,只需要采用最小生成树的思想,对最小生成树的各条边进行Dijstra算法即可。

/*方法二,使用并查集,因为后面边的长度比前面所有边长之和还要长*/
/*所以后面加的边就不用再考虑,如果两个点不属于一个集合,*/
/*直接合并这两个点即可,此时长度一定是最短的*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <climits>
#include <queue>using namespace std;const int MAXN=100+20;
const int MOD=100000;
const int INF=INT_MAX;
int father[MAXN];
int height[MAXN];void Initial(){for(int i=0;i<MAXN;i++){father[i]=i;height[i]=1;}return;
}
int Find(int x){if(father[x]!=x){father[x]=Find(father[x]);}return father[x];
}
void Union(int x,int y){x=Find(x);y=Find(y);if(x==y){return;}if(height[x]<height[y]){father[x]=y;}else if(height[x]>height[x]){father[y]=x;}else{father[x]=y;height[y]++;}return;
}
struct Point{int number=0;int distance;Point(int n,int d):number(n),distance(d){}bool operator<(const Point&p)const{return distance>p.distance;}
};
struct Edge{int to;int k;//第几条路Edge(int t,int kt):to(t),k(kt){}Edge(){}bool operator < (Edge e) const{return k<e.k;}
};
vector<Edge> edges[MAXN];
int dis[MAXN];
void Dijstra(int start,int n){fill(dis,dis+n+1,INF);dis[start]=0;priority_queue<Point> Q;Q.push(Point(start,0));while(!Q.empty()){Point p=Q.top();Q.pop();int from=p.number;for(int i=0;i<edges[from].size();i++){int to=edges[from][i].to;int len=edges[from][i].k;if(dis[to]>dis[from]+len){dis[to]=dis[from]+len;Q.push(Point(to,dis[to]));}}}return;
}
int main(){int N,M;scanf("%d%d",&N,&M);int c1,c2;Initial();int len=1;for(int i=0;i<M;i++){scanf("%d%d",&c1,&c2);if(Find(c1)!=Find(c2)){Union(c1,c2);edges[c1].push_back(Edge(c2,len));edges[c2].push_back(Edge(c1,len));}len=(len*2)%MOD;}Dijstra(0,N);for(int i=1;i<N;i++){printf("%d\n",(dis[i]==INF)?-1:dis[i]%MOD);}return 0;
}

11.4.4 习题11.7 I Wanna Go Homw(北京大学复试上机题)

分析:跟前面题思路类似,在松弛算法上添加约束,经过分析可以知道路程中只能移动一次从1->2,不能有2->1的情况,因此添加这层约束即可

#include <iostream>
#include <queue>
#include <cstdio>
#include <climits>using namespace std;const int MAXN=600+10;
const int INF=INT_MAX;
struct Point{int number;int distance;Point(int n,int d):number(n),distance(d){};Point(){};bool operator<(Point p)const{return distance>p.distance;}
};
struct Edge{int to;int length;Edge(int t,int l):to(t),length(l){};Edge(){};
};
vector <Edge>edges[MAXN];
int support[MAXN];
int dis[MAXN];
void Dijstra(int start){dis[start]=0;priority_queue<Point> Q;Q.push(Point(start,dis[start]));while(!Q.empty()){int from=Q.top().number;Q.pop();for(int i=0;i<edges[from].size();i++){int to=edges[from][i].to;int length=edges[from][i].length;if(dis[to]>dis[from]+length&&!(support[from]==2&&support[to]==1)){//这里添加约束,不能从2-1dis[to]=dis[from]+length;Q.push(Point(to,dis[to]));}}}return;
}
void Initial(){for(int i=1;i<=MAXN;i++){edges[i].clear();support[i]=0;dis[i]=INF;}
}
int main(){int N;while(scanf("%d",&N)!=EOF){if(N==0){break;}Initial();int M;scanf("%d",&M);for(int i=0;i<M;i++){int A,B,T;scanf("%d%d%d",&A,&B,&T);edges[A].push_back(Edge(B,T));edges[B].push_back(Edge(A,T));}for(int i=1;i<=N;i++){scanf("%d",&support[i]);}Dijstra(1);printf("%d\n",dis[2]==INF?-1:dis[2]);}return 0;
}

11.5 拓扑排序

方法
在这里插入图片描述
例子
在这里插入图片描述

11.5.1 例题 11.9 确定比赛名次

杭电-1285 hoj

拓扑排序代码模板

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>using namespace std;const int MAXN =500+10;vector<int>graph[MAXN];
int inDegree[MAXN];vector<int> TopologicalSort(int n){vector<int> togolopy;priority_queue<int,vector<int>,greater<int> >node;for(int i=1;i<=n;i++){if(inDegree[i]==0){node.push(i);}}while(!node.empty()){int u=node.top();node.pop();togolopy.push_back(u);for(int i=0;i<graph[u].size();i++){int v=graph[u][i];inDegree[v]--;if(inDegree[v]==0){node.push(v);}}}return togolopy;
}int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){memset(graph,0,sizeof(graph));memset(inDegree,0,sizeof(inDegree));while(m--){int from,to;scanf("%d%d",&from,&to);graph[from].push_back(to);inDegree[to]++;}vector<int> answer=TopologicalSort(n);for(int i=0;i<answer.size();i++){if(i==0){printf("%d",answer[i]);}else{printf(" %d",answer[i]);}}printf("\n");}return 0;
}

11.5.2 例题 11.8 Legal or Not(拓扑排序判环)

题目描述
ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many “holy cows” like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When someone has questions, many warm-hearted cows like Lost will come to help. Then the one being helped will call Lost “master”, and Lost will have a nice “prentice”. By and by, there are many pairs of “master and prentice”. But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not?
We all know a master can have many prentices and a prentice may have a lot of masters too, it’s legal. Nevertheless,some cows are not so honest, they hold illegal relationship. Take HH and 3xian for instant, HH is 3xian’s master and, at the same time, 3xian is HH’s master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not.
Please note that the “master and prentice” relation is transitive. It means that if A is B’s master ans B is C’s master, then A is C’s master.

Input
The input consists of several test cases. For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100). Then M lines follow, each contains a pair of (x, y) which means x is y’s master and y is x’s prentice. The input is terminated by N = 0.
TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,…, N-1). We use their numbers instead of their names.

Output
For each test case, print in one line the judgement of the messy relationship.
If it is legal, output “YES”, otherwise “NO”.

Sample Input
3 2
0 1
1 2
2 2
0 1
1 0
0 0
Sample Output
YES
NO

题目分析
请添加图片描述

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>using namespace std;const int MAXN=500;vector<int>graph[MAXN];
int inDegree[MAXN];//入度bool TopologicalSort(int n){queue<int> node;for(int i=0;i<n;i++){if(inDegree[i]==0){node.push(i);}}int number=0;//拓扑序列顶点个数while(!node.empty()){int u=node.front();node.pop();number++;for(int i=0;i<graph[u].size();i++){int v=graph[u][i];inDegree[v]--;if(inDegree[v]==0){node.push(v);}}}return n==number;
}
int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){if(n==0&&m==0){break;}memset(graph,0,sizeof(graph));memset(inDegree,0,sizeof(inDegree));while(m--){int from,to;scanf("%d%d",&from,&to);graph[from].push_back(to);inDegree[to]++;}if(TopologicalSort(n)){printf("YES\n");}else{printf("NO\n");}}return 0;
}

11.6 关键路径

区别在这里插入图片描述
关键路径
在这里插入图片描述
在这里插入图片描述

11.6.1 例题11.10 Instructions Arrangement

hdu - 4109

分析请添加图片描述

关键路径模板代码

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <climits>using namespace std;const int MAXN=1001;
const int INF=INT_MAX;struct Edge{int to;//终点int length;//距离Edge(int t,int l):to(t),length(l){}
};vector<Edge> graph[MAXN];
int earliest[MAXN];//最早开始时间
int latest[MAXN];//最晚开始时间
int inDegree[MAXN];//入度void CriticalPath(int n){vector<int> topology;//拓扑序列queue<int> node;for(int i=0;i<n;i++){if(inDegree[i]==0){node.push(i);earliest[i]=1;//初始化为1}}while(!node.empty()){int u=node.front();topology.push_back(u);node.pop();for(int i=0;i<graph[u].size();i++){int v=graph[u][i].to;int length=graph[u][i].length;earliest[v]=max(earliest[v],earliest[u]+length);inDegree[v]--;if(inDegree[v]==0){node.push(v);}}}for(int i=topology.size()-1;i>=0;i--){//求解最迟开始时间int u=topology[i];if(graph[u].size()==0){latest[u]=earliest[u];//汇点的最晚开始时间初始化}else{latest[u]=INF;//非汇点的最晚开始时间初始化}for(int j=0;j<graph[u].size();j++){int v=graph[u][j].to;int len=graph[u][j].length;latest[u]=min(latest[u],latest[v]-len);}}
}
int main(){int n,m;while(scanf("%d%d",&n,&m)!=EOF){memset(graph,0,sizeof(graph));memset(earliest,0,sizeof(earliest));memset(latest,0,sizeof(earliest));memset(inDegree,0,sizeof(inDegree));while(m--){int from,to,length;scanf("%d%d%d",&from,&to,&length);graph[from].push_back(Edge(to,length));inDegree[to]++;}CriticalPath(n);int answer=0;for(int i=0;i<n;i++){answer=max(answer,earliest[i]);}printf("%d\n",answer);}return 0;
}

说明:对于最早时间的初始化,如果题目没有特殊要求,那么所有结点都初始化为0,对于最晚时间的初始化,如果题目没有特殊要求,那么汇点最晚开始时间初始化为它的最早开始时间,其他节点初始化为INF

11.7 小结

在这里插入图片描述


http://chatgpt.dhexx.cn/article/gtsCcxXQ.shtml

相关文章

2021王道考研pdf

参考一&#xff1a;&#xff08;2021&#xff09; https://www.bilibili.com/read/cv5517739/ 计算机考研王道天勤PDF百度网盘&#xff08;数据结构、操作系统、计算机组成原理、计算机网络&#xff09;&#xff08;&#xff01;&#xff01;&#xff01;&#xff01;b站这个链…

操作系统笔记(含王道计算机考研——操作系统课件)

操作系统&#xff08;OS&#xff09; 笔记根据B站王道计算机考研——操作系统视频整理所得&#xff0c;视频链接&#xff1a;https://b23.tv/0I2qex视频中所用课件&#xff1a;链接&#xff1a;https://pan.baidu.com/s/101bFWm0Tv0emNpEneidYPA 提取码&#xff1a;y3dd笔记md…

一篇学完:王道考研408计算机网络(全)

笔记首发于&#xff1a;lengyueling.cn PDF版本附在 lengyueling.cn 对应文章结尾&#xff0c;欢迎下载访问交流 网络体系结构 概念与功能 网络&#xff1a;网样的东西或者网站系统 计算机网络&#xff1a;是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设…

24考研王道计算机组成原理笔记

24考研王道计算机组成原理笔记 文章目录 24考研王道计算机组成原理笔记前言一、计算机系统概述1.1 计算机的发展1.2 计算机硬件1.2.1 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机系统的层次结构 1.3 计算机性能指标1.3.1 存储器性能指标1.3.2 CPU性能指标1.3.3 …

2023年计算机考研专业课408 - 王道书资源做题本OneNote电子笔记

&#x1f4bb;cs-408 构建本仓库的初衷是记录自己备考计算机专业课408的过程本仓库收纳了2023年四本王道复习指导书和2023年王道书上的刷题本本仓库分享了一些自己从2022年6月备考以来的学习408心得本仓库分享了自己使用OntNote制作的电子笔记 希望本仓库的一些经验和资源能够…

考研408 王道计算机考研 (初试/复试) 网课笔记总结

计算机初试、复试笔记总结&#xff08;导航栏&#xff09;&#x1f4dd; 408 考研人&#xff0c;人狠话不多&#xff1a;3、2、1&#xff0c;上链接 &#xff01; 408 考研初试 - 备战期&#xff0c;专业课笔记&#xff0c;导航&#x1f6a5;&#x1f6a5;&#x1f6a5; &…

2023考研计算机408王道考研网盘资源

23考研王道考研计算机408网盘资源&#xff0c;关注【小黑马资料库】工粽号&#xff0c;获取全部资料吧&#xff01; 在父亲眼里&#xff0c;他自己成绩优秀是理所当然的&#xff0c;因此他无法容忍自己的儿子头脑不聪明且成绩不优秀。因此&#xff0c;类似于“我很笨&#xff…

数据结构(王道计算机考研笔记)

一、数据结构概念&#xff1a; 对数据之间的关系的结构类型进行总结归纳。 学好这门课&#xff0c;让我们成为信息革命的参与者。 名词解析&#xff1a; 数据项&#xff1a;您申请一个微博账号&#xff0c;其中姓名&#xff0c;性别这些就是数据项 组合项&#xff1a;您账号…

计算机网络:王道考研

前言 计算机考研课程408包括计组、计网、操作系统、数据结构与算法&#xff0c;计组在21年就补完了——计算机组成原理&#xff1a;最详细笔记&#xff01;&#xff0c;数据结构与算法、操作系统都看了&#xff0c;就差计网这个八股文,系统的听了一遍考研课程《王道-计算机网络…

王道计算机考研——计算机组成原理笔记

计算机组成原理 1.计算机系统概述1. 计算机发展历程2.计算机系统的组成3.存储器4.运算器5. 控制器6. 计算机的工作过程&#xff08;重点&#xff09;7. 计算机的层次结构8.计算机的性能指标1. 存储器2. CPU3.系统整体的性能指标4. 思考 2. 数据的表示和运算1.进位计数制2.BCD码…

王道计算机网络总结

文章目录 第一章 计算机网络体系结构概念&功能 第二章 物理层物理层基本概念接口特性&#xff1a;通讯方式&#xff1a;编码与调制 数据交换方式电路交换报文交换分组交换数据报方式虚电路方式 数据交换的三种方式 传输介质物理层设备 第三章 数据链路层封装成帧差错控制流…

王道考研计算机组成原理(转载)

计算机组成原理比较经典的书籍有&#xff1a; 唐朔飞的《计算机组成原理》、《计算机组成原理——学习指导与习题解答》自中英的《计算机组成原理》李春葆的《计算机组成原理联考辅导教程》 第一章 计算机系统概述 【复习提示】 本章是组成原理的概述&#xff0c;考查时易针…

【专栏必读】王道考研408数据结构+计算机算法设计与分析万字笔记、题目题型总结、注意事项、目录导航和思维导图

王道考研复习指导下载&#xff08;密码7281&#xff09; 其他科目导航 【专栏必读】王道考研408计算机组成原理万字笔记&#xff08;从学生角度辅助大家理解&#xff09;&#xff1a;各章节导航及思维导图 【专栏必读】王道考研408操作系统万字笔记&#xff08;从学生角度辅助…

方差(variance)、标准差(Standard Deviation)、均方差、均方根值(RMS)、均方误差(MSE)、均方根误差(RMSE)

方差&#xff08;variance)&#xff1a;衡量随机变量或一组数据时离散程度的度量。概率论中方差用来度量随机变量和其数学期望&#xff08;即均值&#xff09;之间的偏离程度。统计中的方差&#xff08;样本方差&#xff09;是每个样本值与全体样本值的平均数之差的平方值的平均…

均方误差、平方差、方差、均方差

均方误差、平方差、方差、均方差、协方差 一&#xff0c;MSE&#xff08;均方误差&#xff09;&#xff08;Mean Square Error&#xff09; 均方误差也叫方法损失函数或者最小二乘法 作为机器学习中常常用于损失函数的方法&#xff0c;均方误差频繁的出现在机器学习的各种算法中…

如何计算均值、标准差和标准误差

收集数据后&#xff0c;你要做的第一件事往往就是对它进行分析。这通常都免不了要计算均值、标准差和标准误差。本文将向你展示如何计算。 方法1 数据 1 获得一组你想要分析的数据。这些信息也称为样本。 例如&#xff0c;一个由5个学生组成的班级接受了一次测试&#xff0c;测…

方差、标准差、均方差、均方误差区别总结

一、百度百科上方差是这样定义的: (variance)是在概率论和统计方差衡量随机变量或一组数据时离散程度的度量。概率论中方差用来度量随机变量和其数学期望(即均值)之间的偏离程度。统计中的方差(样本方差)是各个数据分别与其平均数之差的平方的和的平均数。在许多实际问题…

均方误差、平方差、方差、均方差、协方差

一&#xff0c;均方误差 作为机器学习中常常用于损失函数的方法&#xff0c;均方误差频繁的出现在机器学习的各种算法中&#xff0c;但是由于是舶来品&#xff0c;又和其他的几个概念特别像&#xff0c;所以常常在跟他人描述的时候说成其他方法的名字。 均方误差的数学表达为…

机器学习模型中的评价指标

1、回归模型 1.1 MSE&#xff08;均方误差&#xff09; MSE是Mean Square Error的缩写&#xff0c;其计算公式如下&#xff1a; m s e 1 m ∑ i 1 m ( y i − y i ^ ) 2 mse\frac{1}{m} \sum_{i1}^{m}(y_i-\hat{y_i})^2 msem1​i1∑m​(yi​−yi​^​)2 从计算公式可以看出…

品尝当下国外最受欢迎的开源论坛系统phpBB

phpBB是时下开源论坛中使用最多的一个了。phpBB及其强大&#xff0c;功能齐全&#xff0c;界面优雅&#xff0c;用户友好&#xff0c;非常适合没有编程经验的人去搭建论坛。官网中还提供了许多漂亮的 style 和 功能 plug-in 。官网地址&#xff1a;https://www.phpbb.com 最近…