2020.8.21-2020.9.6 the first version
1 闰年
(year % 4 == 0 && year % 100 != 0) || (year % 400 = 0)
预处理每个月的天数,用空间换时间
int daytab[2][13]={ {0,31,28,31,30,31,30,31,31,30,31,30,31} {0,31,29,31,30,31,30,31,31,30,31,30,31} }
2 保留几位输出
3.C语言读取text文件
#include<iostream> #include<stdio.h> using namespace std; int main(){ //逐行写 FILE *fp = NULL; char buffw[26]; fp = fopen("1.txt", "w+"); for(int i=0;i<26;i++){ buffw[i]='a'+i; } //fprintf(fp, "This is testing for fprintf... "); fputs(buffw,fp); fclose(fp); //逐行读 //FILE *fp=NULL; char buffr[255]; fp = fopen("D:\devcpp\baoyan\1.txt", "r"); while(!feof(fp)){ fgets(buffr,255,fp); // printf("%s ", buff); cout<<buffr; } fclose(fp); }c++读取文件首选
#include<iostream> #include<fstream> #include<stdio.h> using namespace std; int main(){ //写入 fstream wfile; wfile.open("1.txt"); char sdata[26]; for(int i=0;i<26;i++){ sdata[i]='z'-i; wfile << sdata[i]<<endl; } //cout<<sdata<<endl; wfile.close(); //读取 string data=""; fstream rfile; rfile.open("1.txt"); //rfile.getline(data,27);//读取num-1个字符 while (getline(rfile,data)) cout << data << endl; rfile.close(); return 0; }
4.vector容器
//vector容器 #include<iostream> #include<vector> #include<algorithm> using namespace std; int main(){ vector<int>obj; vector<int>::iterator it; for(int i=5;i>=0;i--){ obj.push_back(i); } //sort(obj.begin(),obj.end()); for(it=obj.begin();it!=obj.end();it++){ cout<<*it<<" "; } return 0; }
5 sort函数
sort(first,last,comp)
起始地址first,last
comp 排序方式默认升序
重写sort函数可以变为降序
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; bool compare(int a,int b) { return a>b; //升序排列,如果改为return a>b,则为降序 } int main(){ int n=5; int arr[n]; for(int i = 0; i < n; i++){ scanf("%d",&arr[i]); } sort(arr,arr+n,compare); for(int i = 0; i < n; i++){ printf("%d ",arr[i]); } return 0; }compare函数:
比较函数,在遇到新的排序规则时,黄金法则:当比较函数返回值为true时,表示比较函数是第一个参会将排在第二个参数前面。
#include<iostream> #include<algorithm> #include<string> using namespace std; struct student{ string name; int grade; int order; }; bool compare1(student a,student b){ if(a.grade==b.grade){ return a.order<b.order; } else{ return a.grade>b.grade; } } bool compare2(student a,student b){ if(a.grade==b.grade){ return a.order<b.order; } else{ return a.grade<b.grade; } } int main(){ int n; int func; cin>>n>>func; student stu[n]; for(int i=0;i<n;i++){ cin>>stu[i].name>>stu[i].grade; stu[i].order=i; } if(func==0){ sort(stu,stu+n,compare1); }else{ sort(stu,stu+n,compare2); } for(int i=0;i<n;i++){ cout<<stu[i].name<<" "<<stu[i].grade<<endl; } return 0; }
6.二分查找
在查找次数很多的情况下,二分查找优于线性查找
二分查找需要先排序,再查找;
while(left<=right){注意二分法退出循环的条件。
#include<iostream> #include<algorithm> using namespace std; int BinarySearch(int a,int num[],int n){ int left=0; int right=n-1; int mid=(left+right)/2; while(left<=right){ if(num[mid]==a){ return 1; } else if(num[mid]<a){ left=mid+1; }else{ right=mid-1; } mid=(left+right)/2; } return 0; } int main(){ int n,m; while(cin>>n){ int arr[n]; for(int i=0;i<n;i++){ cin>>arr[i]; } sort(arr,arr+n); cin>>m; int num,target; for(int i=0;i<m;i++){ cin>>num; target=BinarySearch(num,arr,n); if(target==1){ cout<<"YES"<<endl; }else{ cout<<"NO"<<endl; } } } return 0; }
7.字符串string
string
插入删除
长度
#include<iostream> #include<string> using namespace std; int main(){ string str="Hello World!"; int n=str.length();//长度 str.insert(0, "zq");//把"zq"插入到位置"0" //cout<<str; str.erase(0,2);//删除从位置0开始的2个字符 str.clear(); cout<<str; return 0; }
常用函数
find()
没找到返回-1
substr()
下标从0开始
#include<iostream> #include<string> using namespace std; int main(){ string str="Hello World!"; int found=str.find("Hello"); cout<<found<<endl; string str1=str.substr(0,5); cout<<str1; return 0; }
常见应用
- 字符串处理
巧用ASCII码计算
#include<iostream> #include<string> using namespace std; int main(){ string str1,str2; cin>>str1>>str2; int len1,len2; len1=str1.length(); len2=str2.length(); int sum=0; for(int i=0;i<len1;i++){ for(int j=0;j<len2;j++){ sum=sum+(str1[i]-'0')*(str2[j]-'0'); } } cout<<sum; return 0; }
- getline()可以获取一行带空格的字符串,cin>>str遇到空格就会停止输入
#include<iostream> #include<string> #include<algorithm> using namespace std; int main(){ string str; int sym; while(getline(cin,str)){ for(int i=0;i<str.length();i++){ if(str[i]<='z'&&str[i]>='a'){ sym=str[i]-'a'; sym=(sym+1)%26; str[i]='a'+sym; } if(str[i]<='Z'&&str[i]>='A'){ sym=str[i]-'A'; sym=(sym+1)%26; str[i]='A'+sym; } } for(int i=0;i<str.length();i++){ cout<<str[i]; } cout<<endl; } return 0; }
- 循环平移
取余的方法P49
- 字母出现次数统计
用一个number数组统计各个出现的概率
学会构造辅助数组
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; int num[128];//128个ASCII码 int main(){ string str1,str2; while(getline(cin,str1)){ if(str1 == "#"){ break; } getline(cin,str2); memset(num,0,sizeof(num)); for(int i=0;i<str2.size();i++){ num[str2[i]]++; } for(int i=0;i<str1.size();i++){ printf("%c %d ",str1[i],num[str1[i]]); } } return 0; }
- int的范围
int有32位,2^32-1,注意int的范围使用
注意pow函数,需要头文件<math.h>,pow(2,n);
#include<iostream> #include<string> #include<algorithm> #include<math.h> using namespace std; int main(){ string s; while(cin>>s){ int sum=0; for(int i=0;i<s.length();i++){ if(s[i]=='0')continue; sum=sum+(s[i]-'0')*(pow(2,s.length()-i)-1); } cout<<sum<<endl; } }
- 首字母大写问题
复习:注意getline函数的使用(C语言可以用gets)
大写与小写字母的ASCII差值的使用
#include<iostream> #include<string> #include<algorithm> using namespace std; int main(){ string s; int p; while(getline(cin,s)){ if(s[0]>='a'&&s[0]<='z'){ p=s[0]+'A'-'a'; s[0]=p; } for(int i=1;i<s.size();i++){ if(s[i]==' '||s[i]==' '||s[i]==' '||s[i]==' '){ i=i+1; if(s[i]>='a'&&s[i]<='z'){ p=s[i]+'A'-'a'; s[i]=p; } else{ i=i-1; } } } cout<<s; } }
字符串匹配
kmp算法
重点理解next数组的求法
#include<iostream> #include<string> #include<algorithm> //KMP算法 using namespace std; const int MAXM=10000; const int MAXN=1000000; int nextTable[MAXM]; int pattern[MAXM]; int text[MAXN]; //创建next表 void GetNextTable(int m){ int j=0; nextTable[j]=-1; int i=-1; while(j<m){ if(i==-1||pattern[i]==pattern[j]){ i++; j++; nextTable[j]=i; }else{ i=nextTable[i]; } } } int main(){ return 0; }
8 数据结构一
向量
vector
主要应用于不知道需要多大数组的方法
#include<vector>push_back()
pop_back()
empty()
size()
insert()
erase()
clear()
begin()
end()
#include<iostream> #include<string> #include<vector> using namespace std; vector<int>obj; int main(){ for(int i=0;i<5;i++){ obj.push_back(i); } obj.insert(obj.begin(),3,15); obj.pop_back(); for(int i=0;i<obj.size();i++){ cout<<obj[i]<<endl; } obj.erase(obj.begin()+5,obj.end()); vector<int>::iterator it; for(it=obj.begin();it!=obj.end();it++){ cout<<*it<<" "; } obj.clear(); return 0; }https://www.nowcoder.com/practice/ccc3d1e78014486fb7eed3c50e05c99d?tpId=60&tqId=29492&tPage=1&ru=/kaoyan/retest/1001&qru=/ta/tsing-kaoyan/question-ranking
求因数
#include<iostream> #include<vector> using namespace std; int s(int x){ int sum=0; for(int i=1;i<=x/2;i++){ if(x%i==0){ sum=sum+i; } } //cout<<sum<<endl; return sum; } int main(){ vector<int>obj1; vector<int>obj2; for(int i=2;i<=60;i++){ if(i==s(i)){ obj1.push_back(i); }else if(i<s(i)){ obj2.push_back(i); } } cout<<"E"<<":"; for(int i=0;i<obj1.size();i++){ cout<<" "<<obj1[i]; } cout<<endl; cout<<"G"<<":"; for(int i=0;i<obj2.size();i++){ cout<<" "<<obj2[i]; } return 0; }
队列
STL-queue
#include<queue>
queue<type>name
empty()
size()
push()
pop()
front()
back()
队头删除元素
队尾添加元素
队列应用约瑟夫问题
循环队列
案例
#include<iostream> #include<queue> #include<algorithm> using namespace std; //模拟循环队列 int main(){ int n,p,m; while(cin>>n>>p>>m){ if(n==0&&p==0&&m==0){ break; } queue<int>children; for(int i=1;i<=n;i++){ children.push(i);//加入编号 } for(int i=1;i<p;i++){ children.push(children.front()); children.pop();//把编号为p的放在第一位 } while(!children.empty()){ for(int i=1;i<m;i++){//m-1个小孩重新入队 children.push(children.front()); children.pop(); } if(children.size()==1){ cout<<children.front()<<endl; }else{ cout<<children.front()<<','; } children.pop(); } } return 0; }
栈
stack
stack<typename>name
empty()
size()
push()
back()
top()和队列不同的地方,只能访问栈顶
栈的应用
无法实现确定存放容器的大小
逆序输出
注意:int最大值:2^31-1=214748364(9位)
long long 最大值 2^64-1=9223372036854775807(19位)
#include<iostream> #include<string> #include<algorithm> #include<stack> using namespace std; stack<long long>st;//用long long int main(){ int n; while(cin>>n){ for(int i=0;i<n;i++){ long long num; cin>>num; st.push(num); } while(!st.empty()){ cout<<st.top()<<" "; st.pop(); } cout<<endl; } return 0; }
括号匹配
括号左右匹配
表达式求值
简单计算器
用栈解决
数据栈
符号栈
#include<iostream> #include<algorithm> #include<stack> #include<string> #include<iomanip> using namespace std; int pr(char c){//优先级顺序 if(c=='#'){ return 0; }else if(c=='$'){ return 1; }else if(c=='+'||c=='-'){ return 2; }else{ return 3; } } //取参与运算的数据 double getNumber(string s,int &index){ double number=0; while(s[index]>='0'&&s[index]<='9'){ number=number*10+s[index]-'0'; index++; } return number; cout<<1; cout<<number<<endl; } //计算 double Calculate(double x,double y,char op){ double result=0; if(op=='+'){ result=x+y; }else if(op=='-'){ result=x-y; }else if(op=='*'){ result=x*y; }else if(op=='/'){ result=x/y; } return result; } int main(){ string str; while(getline(cin,str)){ if(str=="0"){ break; } int index=0;//字符串处理定位 stack<double>data;//数据栈 stack<char>op;//运算符栈 str=str+'$'; op.push('#'); //cout<<str; while(index<str.size()){ if(str[index]==' '){ index++; }else if(str[index]>='0'&&str[index]<='9'){ data.push(getNumber(str,index)); //cout<<str; //cout<<data.top(); //cout<<"zq"; }else{ if(pr(op.top())<pr(str[index])){ op.push(str[index]); index++; //cout<<str; }else{ double y=data.top();//x和y顺序不能反 data.pop(); double x=data.top(); data.pop(); //cout<<str; data.push(Calculate(x,y,op.top())); op.pop(); //cout<<str; } } } //cout<<op.top(); cout<<fixed<<setprecision(2)<<data.top()<<endl; } return 0; }
9 数学问题
进制转换
字符串的加减乘除
//author:Q_Zhang #include<iostream> #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 num=remainder*10+str[i]-'0';//每一步余数与下一位的组合 str[i]=num/x+'0';//除法运算 remainder=num%x;//在这一位的余数 } int pos=0; cout<<remainder<<endl; while(str[pos]=='0'){//去除产生多余的0 pos++; } return str.substr(pos); } int main(){ string x; cin>>x; x=Divide(x,5); cout<<x; return 0; }
最大公约数,最小公倍数
辗转相除法求最大公约数
两数乘积除以最大公约数即为最小公倍数
非递归
#include<iostream> using namespace std; int max(int a,int b){ int r; if(a<b){ r=a; a=b; b=r; } r=a%b; while(r!=0){ a=b; b=r; r=a%b; } return b; } int main(){ int m,n,result; while(cin>>m>>n){ result=max(m,n); cout<<result<<endl; } return 0; }递归很简单自行查阅
质数
素数筛法
找到一个素数,就将它所有倍数均标记为非素数,则判定其为素数,并标记它的所有倍数为非素数,然后继续遍历
#include<iostream> #include<vector> using namespace std; const int MAXN=10001; vector<int>prime; bool isPrime[MAXN]; void Init(){ for(int i=0;i<MAXN;i++){ isPrime[i]=true; } isPrime[0]=false; isPrime[1]=false; for(int i=2;i<MAXN;i++){ if(!isPrime[i]){ continue; } prime.push_back(i); for(int j=i*i;j<MAXN;j=j+i){ isPrime[j]=false; } } } int main(){ Init(); int n; bool output=false; while(cin>>n){ for(int i=0;i<prime.size();i++){ if(prime[i]>=n){ break; } else if(prime[i]%10==1){ output=true; cout<<prime[i]<<" "; } } if(!output){ cout<<-1; } cout<<endl; } return 0; }
质数判断
#include<iostream> #include<cmath> using namespace std; bool Judge(int x){ if(x<2){ return false; } int bound=sqrt(x); for(int i=2;i<=bound;i++){ if(x%i==0){ return false; } } return true; } int main(){ int n; bool s; while(cin>>n){ s=Judge(n); if(s){ cout<<"yes"<<endl; }else{ cout<<"no"<<endl; } } return 0; }
分解质因数
、
#include<iostream> #include<algorithm> #include<cmath> using namespace std; int main(){ int n; while(cin>>n){ int num=0; int bound=sqrt(n); for(int i=2;i<=bound;i++){ while(n%i==0){ num++; n=n/i; } } if(n!=1)num++;//特别注意:如果n为质数的情况下 cout<<num<<endl; } return 0; }
快速幂
核心思想:将指数化为2进制数,1对应的位是快速求幂的分解的指数
#include<iostream> #include<cmath> #include<algorithm> using namespace std; int Fast(int a,int b,int mod){ int answer=1; while(b!=0){ //核心思想:转化为2进制 if(b%2==1){ answer=answer*a; answer=answer%mod; } b=b/2; a=a*a; a=a%mod; } return answer; } int main(){ int a,b; while(cin>>a>>b){ if(a==0&&b==0){ break; } cout<<Fast(a,b,1000)<<endl; } return 0; }
原理同快速幂,初始状态为单位矩阵
大整数的加减乘除 重要
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; void Switch(string &a,string &b){ string c=a; a=b; b=c; } int main(){ string a,b; int len1,len2,p; while(cin>>a>>b){ vector<int>obj; len1=a.size(); len2=b.size(); if(len2<len1){ Switch(a, b); } int remain=0; int i=a.size()-1;//特别注意:交换过后需要重新求解长度 int j=b.size()-1; for(;i>=0;i--,j--){ p=a[i]-'0'+b[j]-'0'+remain; if(p>=10){ remain=1; p=p-10; obj.push_back(p); }else{ obj.push_back(p); remain=0; } } for(;j>=0;j--){ p=b[j]-'0'+remain; if(p>=10){ remain=1; p=p-10; obj.push_back(p); }else{ obj.push_back(p); remain=0; } } if(remain==1){ obj.push_back(1); } for(int k=obj.size()-1;k>=0;k--){ cout<<obj[k]; } obj.clear(); cout<<endl; } return 0; }第二种思路:进位统一处理
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; void Switch(string &a,string &b){ string c=a; a=b; b=c; } int main(){ string a,b; int len1,len2,p; while(cin>>a>>b){ vector<int>obj; len1=a.size(); len2=b.size(); if(len2<len1){ Switch(a, b); } int remain=0; int i=a.size()-1; int j=b.size()-1; for(;i>=0;i--,j--){ p=a[i]-'0'+b[j]-'0'+remain; if(p>=10){ remain=1; p=p-10; obj.push_back(p); }else{ obj.push_back(p); remain=0; } } for(;j>=0;j--){ p=b[j]-'0'+remain; if(p>=10){ remain=1; p=p-10; obj.push_back(p); }else{ obj.push_back(p); remain=0; } } if(remain==1){ obj.push_back(1); } for(int k=obj.size()-1;k>=0;k--){ cout<<obj[k]; } obj.clear(); cout<<endl; } return 0; }乘法稍微改一下就成
#include<iostream> #include<string> using namespace std; int main(){ string a,b; int len1,len2,len3,i,j,k=0; cin>>a; cin>>b; len1=a.length(); len2=b.length(); len3=len1+len2; int aa[len1+1]={0},bb[len2+1]={0},cc[len3+1]={0}; for(i=1;i<=len1;i++){ aa[i]=a[len1-i]-'0'; } for(i=1;i<=len2;i++){ bb[i]=b[len2-i]-'0'; } for(i=1;i<=len1;i++){ for(j=1;j<=len2;j++){ cc[i+j-1]=cc[i+j-1]+aa[i]*bb[j]; //小技巧要注意 } } for(i=1;i<=len3;i++){ cc[i+1]=cc[i+1]+cc[i]/10; cc[i]=cc[i]%10; } while(len3>0&&cc[len3]==0){ len3--; } if(len3==0){ cout<<0<<endl; } else{ for(i=len3;i>0;i--){ cout<<cc[i]; } cout<<endl; } return 0; }
10 贪心策略
最优时间分配:选择结束时间最早的
11 递归与分治
1.子问题要与原始问题相同
2.不能无限制调用本身,必须有个递归出口
阶乘可以用递归
汉诺塔
后期总结补充
分治法
斐波那契数列
#include<iostream> #include<algorithm> 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(cin>>n){ cout<<Fibonacci(n)<<endl; } }
子树有多少个节点问题
12 搜索(难度较大,掌握后level上升一个台阶)
广度优先搜索BFS
需要有访问标记
玛雅密码
深度优先搜索DFS
八皇后问题
13 数据结构二
二叉树的遍历
#include<iostream> #include<algorithm> #include<queue> using namespace std; struct TreeNode{ int data; TreeNode *leftChild; TreeNode *rightChild; }; //前序遍历 void PreOrder(TreeNode *root){ if(root==NULL){ return; } cout<<root->data; PreOrder(root->leftChild); PreOrder(root->rightChild); return; } //中序遍历 void InOrder(TreeNode *root){ if(root==NULL){ return; } InOrder(root->leftChild); cout<<root->data; InOrder(root->rightChild); return; } //后序遍历 void PostOrder(TreeNode *root){ if(root==NULL){ return; } PostOrder(root->leftChild); PostOrder(root->rightChild); cout<<root->data; return; } //层序遍历 void LevelOrder(TreeNode *root){ queue<TreeNode *>myQueue; if(root!=NULL){ myQueue.push(root); } while(!myQueue.empty()){ TreeNode *current=myQueue.front(); myQueue.pop(); cout<<current->data; if(current->leftChild!=NULL){ myQueue.push(current->leftChild); } if(current->rightChild!=NULL){ myQueue.push(current->rightChild); } } return; } int main(){ return 0; }
通过先序遍历和中序遍历构建树
https://www.nowcoder.com/questionTerminal/6e732a9632bc4d12b442469aed7fe9ce(未理解)
#include<iostream> #include<algorithm> using namespace std; struct TreeNode{ char data; TreeNode *leftChild; TreeNode *rightChild; TreeNode(char c): data(c),leftChild(NULL),rightChild(NULL){} }; TreeNode *Build(string str1,string str2){ if(str1.size()==0){ return NULL; } char c = str1[0]; TreeNode *root=new TreeNode(c); int posion=str2.find(c); root->leftChild=Build(str1.substr(1,posion),str2.substr(0,posion)); root->rightChild=Build(str1.substr(posion+1), str2.substr(posion+1)); return root; } void PostOrder(TreeNode *root){ if(root==NULL){ return; } PostOrder(root->leftChild); PostOrder(root->rightChild); cout<<root->data; return; } int main(){ string str1,str2; while(cin>>str1>>str2){ TreeNode *root = Build(str1,str2); PostOrder(root); cout<<endl; } return 0; }
二叉排序树
https://www.nowcoder.com/practice/30a0153649304645935c949df7599602?tpId=69&tqId=29654&tPage=1&ru=/kaoyan/retest/11002&qru=/ta/hust-kaoyan/question-ranking
(weilijie)
#include<iostream> #include<algorithm> using namespace std; struct TreeNode{ int data; TreeNode *leftNode; TreeNode *rightNode; TreeNode(int x): data(x),leftNode(NULL),rightNode(NULL){} }; TreeNode *Insert(TreeNode *root,int x,int father){ if(root==NULL){ root=new TreeNode(x); cout<<father<<endl; }else if(x<root->data){ root->leftNode=Insert(root->leftNode,x,root->data); }else{ root->rightNode=Insert(root->rightNode,x,root->data); } return root; } int main(){ int n; while(cin>>n){ TreeNode *root=NULL; for(int i=0;i<n;i++){ int x; cin>>x; root=Insert(root,x,-1); } } return 0; return 0; }
优先队列
#include<queue>
优先队列的典型应用:
priority_queue<int>myQueue;
默认是大顶堆
哈夫曼树
哈夫曼树需要改为小顶堆,用greater
priority_queue<int,vector<int>,greater<int>>myQueue;
#include<iostream> #include<queue> using namespace std; int main(){ int n; while(cin>>n){ priority_queue<int,vector<int>,greater<int>>myQueue; while(n--){ int x; cin>>x; myQueue.push(x); } int result=0; while(myQueue.size()>1){ int p=myQueue.top(); myQueue.pop(); int q=myQueue.top(); myQueue.pop(); result=result+p+q; myQueue.push(p+q); } cout<<result<<endl; } return 0; }
散列表
#include<map> map<int,int>name; map.empty() map.size() map.insert(); map.erase(); [] at() find() clear() begin() end()
散列表操作
#include<iostream> #include<map> #include<string> using namespace std; map<string,int>myMap; int main(){ myMap["em"]=67; myMap.insert(pair<string,int>("bob",72)); cout<<myMap.size()<<endl; cout<<myMap["bob"]<<endl; cout<<myMap.at("em")<<endl; myMap.erase("em"); map<string,int>::iterator it; for(it = myMap.begin();it!=myMap.end();it++){ cout<<it->first<<' '<<it->second<<endl; } myMap.clear(); it=myMap.find("bob"); if(it==myMap.end()){ cout<<"没找到"; } return 0; }
字串计算
注意substr()的使用
#include<iostream> #include<map> #include<string> using namespace std; int main(){ string str; while(cin>>str){ map<string,int>count; for(int i=0;i<=str.size();i++){ for(int j=0;j<i;j++){ string key=str.substr(j,i-j); count[key]++; } } map<string,int>::iterator it; for(it=count.begin();it!=count.end();it++){ if(it->second>1){ cout<<it->first<<" "<<it->second<<endl; } } } return 0; }
14 图论(really difficult)学会再提升一个level
最小生成树
最短路径 迪杰斯特拉算法
拓扑排序
关键路径
后续更新
(水平有限)
15 动态规划
斐波那契额数列的变体
上楼梯问题
#include<iostream> #include<algorithm> using namespace std; const int MAXN = 92; long long dp[MAXN]; int main(){ dp[0]=0; dp[1]=1; for(int i=2;i<MAXN;i++){ dp[i]=dp[i-1]+dp[i-2]; } int n; while(cin>>n){ cout<<dp[n+1]<<endl; } return 0; }
最大连续子序列和
https://www.nowcoder.com/questionTerminal/df219d60a7af4171a981ef56bd597f7b#include<iostream> #include<algorithm> using namespace std; const int MAXN=1000000; long long arr[MAXN]; long long dp[MAXN]; long long Max(int n){ long long maxs=0; for(int i=0;i<n;i++){ if(i==0){ dp[i]=arr[i]; }else{ dp[i]=max(arr[i],dp[i-1]+arr[i]); } maxs=max(maxs,dp[i]); } return maxs; } int main(){ int n; while(cin>>n){ for(int i=0;i<n;i++){ cin>>arr[i]; } long long answer=Max(n); cout<<answer<<endl; } return 0; }
二维:
https://www.nowcoder.com/practice/1c5fd2e69e534cdcaba17083a5c56335?tpId=61&tqId=29506&tPage=1&ru=/kaoyan/retest/1002&qru=/ta/pku-kaoyan/question-ranking最长递增子序列
设置一个dp[ ]表示以A[ i ]作为末尾的最长递归子序列长度,则最长递增子序列长度是dp[ ]数组中的最大值
两种情况:
A[i]之前的元素都比她大,则dp[ i ]=1;
之前的元素比它小
#include<iostream> using namespace std; const int MAXN=1000; int arr[MAXN]; int dp[MAXN]; int main(){ int n; while(cin>>n){ for(int i=0;i<n;i++){ cin>>arr[i]; } int answer=0; for(int i=0;i<n;i++){ dp[i]=arr[i]; for(int j=0;j<i;j++){ if(arr[j]<arr[i]){ dp[i]=max(dp[i],dp[j]+arr[i]); } } answer=max(answer,dp[i]); } cout<<answer<<endl; } return 0; }
最长公共子序列
dp[ i ] [ j ]表示以S1[i]和S2[j]作为末尾的最长公共子序列长度
s1[i]==s2[j] dp[i][j]=dp[i-1][j-1]+1; s1[i]!=s2[j] dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
#include<iostream> #include<cstring> using namespace std; const int MAXN=1001; char s1[MAXN]; char s2[MAXN]; int dp[MAXN][MAXN]; int main(){ while(scanf("%s%s",s1+1,s2+1)!=EOF){ int n=strlen(s1+1); int m=strlen(s2+1); for(int i=0;i<=n;i++){ for(int j=0;j<=m;j++){ if(i==0||j==0){ dp[i][j]=0; continue; } if(s1[i]==s2[j]){ dp[i][j]=dp[i-1][j-1]+1; }else{ dp[i][j]=max(dp[i][j-1],dp[i-1][j]); } } } cout<<dp[n][m]; } return 0; }
背包问题
0-1背包
(未理解)欢迎交流
(记住)
#include<iostream> using namespace std; const int MAXN=1001; int v[MAXN];//价值 int w[MAXN];//重量 int dp[MAXN]; int main(){ int n,m; while(cin>>m>>n){ for(int i=0;i<n;i++){ cin>>w[i]>>v[i]; } for(int i=0;i<=m;i++){//初始化 dp[i]=0; } for(int i=0;i<n;i++){ for(int j=m;j>=w[i];j--){ //特别注意要逆序遍历 dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } } cout<<dp[m]<<endl; } return 0; }
完全背包
与0-1背包不同,每种物品可以取不止一件
(未理解)
只需将0-1背包的逆向改为正向即可
其他问题
整数拆分
#include<iostream> using namespace std; const int MAXN=1000001; int dp[MAXN]; int main(){ dp[0]=1; dp[1]=1; for(int i=2;i<=MAXN;i++){ if(i%2==0){ dp[i]=(dp[i-1]+dp[i/2])%1000000000; } else{ dp[i]=dp[i-1]; } } int n; while(cin>>n){ cout<<dp[n]<<endl; } return 0; }
2020-9-6于南京NUIST