考研机试题

头文件与STL

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

vector.insert(vector.begin(),2,99)//在头部插入2个99
vector.erase(vector.begin() + 5, vector.end()) //删除第5个以后的元素

map<string,int>
map.insert(pair<string, int>())
map.count() //0或1
map.earse() //删除

string s;
s.find()
s.substr(int start,int length) //切割子串
//输入含空格字符串
getline(cin,s); 
    
    
//优先队列    
priority_queue<int,vecotr<int>,greater<int>>; //less是降序
 

python输入

import sys
for line in sys.stdin:
  arr = line.split()
  list = list(arr[0])
 //拼接列表
  ' '.join(list)
  a = int(arr[0])
    
    
    

动态规划

最大数组子串和

dp[i]其实代表的是以i结尾的最大子串和

for(int i=0;i<n;i++){
    cin>>a[i];
    // 需要额外的ans存储max,因为是子串
    dp[i+1]=max(dp[i]+a[i],a[i]);
    ans=max(dp[i+1],ans);
}

最长公共子序列

for(int i=1;i<=s1.size();i++){
	for(int j=1;j<=s2.size();j++){
        if(s1[i-1]==s2[j-1])dp[i][j]=dp[i-1][j-1]+1;
        else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
	}
}

最长连续公共子串

//t存储公共子串在s1中的末尾位置
int t=0;
//最大长度,要额外的maxLen存储max,因为是子串
int maxLen=0;
for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        if(s1[i-1]==s2[j-1]){
            dp[i][j]=dp[i-1][j-1]+1;
            // =号确保 如果不唯一,则输出s1中的最后一个。
            if(dp[i][j]>=maxLen){
                maxLen=dp[i][j];
                //存储公共子串在s1中的末尾位置,可以输出子串
                t=i-1;
            }
        } 
    }
}

最长递增子序列

https://www.nowcoder.com/practice/cf209ca9ac994015b8caf5bf2cae5c98?tpId=40&tags=&title=&difficulty=0&judgeStatus=0&rp=1&sourceUrl=

dp[i]只代表以i结尾的最长递增子序列数

for(int i=0;i<n;i++){
    //初始化:最长为本身 1
	dp[i]=1;
	for(int j=0;j<i;j++){
        //dp[i]代表以i结尾的最长递增子序列数
		if(a[i]>a[j])dp[i]=max(dp[j]+1,dp[i]);
        ans=max(dp[i],ans);
	}
}

最大上升子序列和

和上述最长递增子序列思路一致,不过dp[i]代表以i结尾的最长递增子序列的和,用ans存储结果

0-1背包

int dp[1001][1001];//代表前i个物体,背包为j的最大价值
int n,bag;
int v[10001],w[10001];
cin>>n>>bag;
for(int i=1;i<=n;i++){
    cin>>v[i]>>w[i];
}
dp[0][0]=0;
for(int i=1;i<=n;i++){
    for(int j=1;j<=bag;j++){
        if(j>=v[i]){
            dp[i][j]=max(dp[i-1][j-v[i]]+w[i],dp[i-1][j]);
        }
        else{
            dp[i][j]=dp[i-1][j];
        }
    }
}
cout<<dp[n][bag];

完全背包

每种物品无限件

for(int i=1;i<=n;i++){
    for(int j=v[i];j<=m;j++){
        dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }
}

多重背包问题 I

第 i 种物品最多有 si件,

//将 si拆成多个物品,即01背包
 while(s--)
{
    a[++t]=v;
    b[t]=w;
}//死拆,把多重背包拆成01背包

整数拆分

一个整数总可以拆分为2的幂的和

//奇数
if(i%2)dp[i]=dp[i-1];
//偶数(有1和没1两种情况)
else dp[i]=(dp[i-1]+dp[i/2])%1000000000;

整数划分

计数类DP

一个整数总可以拆乘a1+a2+…的和 (完全背包问题有多少种方案数

***???

dp[0]=1;
for(int i=1;i<=n;i++){
    for(int j=i;j<=n;j++){
        dp[j]=(dp[j]+dp[j-i])%mod;
    }
}

最小邮票

为了集齐n积分,最小需要几张邮票?

dp[0][0]=0;
for(int i=1;i<=m;i++){
    //代表集不齐
    dp[0][i]=1e9;
}


for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
        if(j-a[i]>=0)
        dp[i][j]=min(dp[i-1][j-a[i]]+1,dp[i-1][j]);
        else
        dp[i][j]=dp[i-1][j];
    }
}
//如果1e9输入0

最大子矩阵

子矩阵的和:pivot - dp[k-1][j] - dp[i][q-1] + dp[k-1][q-1]

 for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> matrix[i][j];
            //计算机前缀和
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i][j];
        }
    }
	
    int  ans = INT_MIN;
    //记录最大子矩阵位置
    int x1,x2,y1,y2;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            int pivot = dp[i][j];
            for (int k = 1; k <= i; k++) {
                for (int q = 1; q <= j; q++) {
                    if((pivot - dp[k-1][j] - dp[i][q-1] + dp[k-1][q-1])>ans){
                        ans = max(ans, pivot - dp[k-1][j] - dp[i][q-1] + dp[k-1][q-1]);
                        x1=k;
                        x2=i;
                        y1=q;
                        y2=j;
                    }
                    
                }
            }
        }
    }
    cout << ans<<endl;
    cout<<x1<<y1<<" "<<x2<<y2<<endl;

买卖股票最佳时机

可以买卖多次

// 持有股票和不持有股票
int dp[100001][2];
dp[0][0]=-prices[0];
dp[0][1]=0;

int n=prices.size();
for(int i=1;i<n;i++){
    dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]);
    dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]);
}
return dp[n-1][1];

数学问题

朴素法筛素数

求n以内的所有素数,时间O(nlog(logn))【不是最优:例如14会被2和7筛重复2次】

void get_primes(int n){
	for(int i=2;i<n;i++){
        //i被筛了,直接跳过
        if(st[i]) continue;
        //i是素数,添加进数组,并筛掉与i成倍数的非素数
        else {primes[cnt ++ ] = i;
            for(int j=2*i;j<=n;j+=i){
                //j一定不是素数
                st[j]=true;
            }
         }
    }
}

线性筛素数

时间O(n), if(i%primes[j]==0) break;解决重复筛

for(int i=2;i<=n;i++){
    //i没被筛,加入
    if(!st[i]) primes[cnt++]=i;
    for(int j=0;j<cnt;++j)
    {
        if(primes[j]*i>n) break;
        //翻倍,一个数 * 素数一定为合数 
        st[primes[j]*i]=true;
        //退出循环,避免之后重复进行筛选
        if(i%primes[j]==0) break;
    }
}

快速幂

int qmi(int a,int b, int p){
    if(b==0)return 1 ; 
    int k = qmi(a,b/2,p)%p;
    // k*k可能会超过int 
    if(b%2==0)return (1LL*k*k) %p;
    else return ((1LL*k*k)%p*a)%p;
    
}

石子合并

区间dp问题

dp[i,j]代表合并i-j的最小代价

s[j]-s[i-1]是合并这两堆的代价

状态转移方程dp[i,j]=min(dp[i,k]+dp[k+1,j]+s[j]-s[i-1])

先枚举距离,再定义左右端点

#include<bits/stdc++.h>
using namespace std;
int main(){
    // dp[i][j]表示合并i~j的最小代价
    int dp[305][305];
    // 前缀和
    int s[1001];
    int a[1001];
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        s[i]=s[i-1]+a[i];
    }
    // 处理边界条件

    // 先枚举区间长度! 再枚举左端点和右端点
    for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            dp[i][j]=1e7;
            for(int k=i;k<=j;k++){
                dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+s[j]-s[i-1]);
            }
        }
    }
    
    
	cout<<dp[1][n]<<endl;
	
}

锯木棍

贪心-思想是WPL最小带权路径,永远合并最小的两个

#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
//自定义比较结构体
struct cmp{
    //函数重载 注意两个括号!!!
	bool operator()(int a,int b){
        //稳定
		if(a==b) return false;
		else return a>b;
		
	}
};

int main(int argc, char** argv) {
    //priority_queue<int,vector<int>,greater<int>> que;
	priority_queue<int,vector<int>,cmp> que;
	int n,l;
	cin>>n>>l;
	int tmp;
	int ans=0;
	while(n--){
		cin>>tmp;
		que.push(tmp);
	}	
	while(que.size()!=1){
		int a=que.top();
		que.pop();
		int b=que.top();
		que.pop();
			
		que.push(a+b);
		ans=ans+a+b;
	}
	cout<<ans;	
	return 0;
}

并查集

int Find(int a){
    int x=a;
    while(s[x]>0){
        x=s[x];
    }
    return x;
}
void Union(int a,int b){
    root1=Find(a);
    root2=Find(b);
    if(root2==root1)return ;
    else{
        s[root2]=root1;
    }
    
}

Dijkstra单源最短路

int g[N][N];  // 存储每条边
int dist[N];  // 存储1号点到每个点的最短距离
bool st[N];   // 存储每个点的最短路是否已经确定

// 求1号点到n号点的最短路,如果不存在则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;

    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;     // 在还未确定最短路的点中,确定一个最短的点
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
    
        // 用t更新其他点的距离
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);
    	
        st[t] = true;
    }
    
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];

}

Python进制转换(整数无限大)

import sys

for line in sys.stdin:
    a = line.split()
    a=int(a[0])
    b=bin(a)
    s=(b[2:][::-1])
    print(int(s,2))
    

全排列

回溯法

void dfs(int k){
	if(k==n+1){
		for(int i=1;i<=n;i++){
			cout<<arr[i]<<' ';
		}
		cout<<'\n';
		return ;
	}
	for(int i=1;i<=n;i++){
		//还没访问的数
		if(!st[i]){
			st[i]=true;
			// 存储第k个数
			arr[k]=i;
			dfs(k+1);
			// 恢复-现场
			st[i]=false;
		}
	}
}
int main() {    
    cin>>n;
    dfs(1);
    
}

神奇的口袋

有一个神奇的口袋,总容积是40,有n个物品,体积为Vi,装满40有多少种装法

void dfs(int u,int j){
    if(u==40){
        ans++;   
    }
    else{
        //从j开始,前面用过的舍弃掉,防止重复
        for(int i=j;i<n;i++){
            if(!st[i]){
                st[i]=true;
                dfs(u+v[i],i);
                st[i]=false;
            }
        }
    }
}

全排列II

带有重复元素的全排列

while(s[i+1]==s[i])i++; //跳过

void dfs(int k){
	if(k==n+1){
		for(int i=1;i<=n;i++){
			cout<<arr[i]<<' ';
		}
		cout<<'\n';
		return ;
	}
	for(int i=1;i<=n;i++){
		//还没访问的数
		if(!st[i]){
			st[i]=true;
			// 存储第k个数
			arr[k]=i;
			dfs(k+1);
			// 恢复-现场
			st[i]=false;
       		
            //***当与后一个元素重复时,跳过不排列,且这一步要在恢复现场之后做
            while(s[i+1]==s[i])i++;
		}
	}
}
int main() {    
    cin>>n;
   //使重复的元素排在一起
    sort(a,a+n);
    dfs(1);
    
}

放苹果

把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?

//处理边界
for(int i=0;i<=m;i++){
    //为0的可以不用处理,数组默认为0
    //1个盘子的
    dp[i][1]=1;
}
for(int i=0;i<=n;i++){
    //0个苹果的
    dp[0][i]=1;
}

for(int i=1;i<=m;i++){
    for(int j=1;j<=n;j++){
        //如果盘子多,多余的用不到的盘子都是没用的
        if(j>i){
            dp[i][j]=dp[i][i];
        }
        //如果苹果多,dp[i][j]等于 有空盘子的(挑一个盘子为空)+没有空盘子(每个盘子初始都放一个苹果)的状态
        else{
            dp[i][j]=dp[i][j-1]+dp[i-j][j];
        }

    }
}

求第k小

使用快排划分的思想

#include <iostream>
#include <algorithm>
/**求第k小 */
using namespace std;
int n;
int a[10001];
int k;
void partition(int start,int end) {
	int pivot=a[start];
	int l=start;
	int r=end;
	while(l<r) {
        while(l<r&&a[r]>pivot) {
			r--;
		}
		while(l<r&&a[l]<=pivot) {
			l++;
		}
        if(l<r) swap(a[l],a[r]);
	}
	swap(a[start],a[l]);
	if(l==k-1) {
		cout<<a[l];
		return ;
	}
	else if(l<k){
		partition(l+1,end);
	}
	else{
		partition(start,l);
	}
}



int main(int argc, char** argv) {
    
	cin>>n;
	cin>>k;
	for(int i=0; i<n; i++) {
		cin>>a[i];
	}
    //数组去重
	partition(0,n-1);
	return 0;
}

八皇后问题

// u代表行,只需要判断同列,左上和右上角
bool judge(int row,int col){

    for(int i=1;i<=8;i++){
        if(st[i][col])return false;
    }
    for(int i=row,j=col;i>=1&&j<=8;i--,j++){
        if(st[i][j]){
            return false;
        }
    }
    for(int i=row,j=col;i>=1&&j>=1;i--,j--){
        if(st[i][j]){
            return false;
        }
    }
    return true;

}

void dfs(int u, string s) {
    if (u > 8) {
        //s输出每一列的位置
        arr.push_back(s);
        return ;
    }
    //按行循环
    for(int j = 1;j<=8;j++){
        if(judge(u, j)){
            st[u][j]=true;
            dfs(u+1,s+char(j+'0'));
            //恢复现场
            st[u][j]=false;
        }
    }
    
}

哈夫曼编码

priority_queue<int,vector<int>,greater<int> q;
int alpha[26];
//去最小的两个

KMP算法

//字符串下标都从0开始
void getNextTable(int m){
    int j=0;
    next[0]=-1;
    int i=-1;
    while(j<m){
        if(i==-1 || pattern[j]==pattern[i]){
            i++;
            j++;
            next[j]=i;
        }
        else{
            i=next[i];
        }
    }
    return ;
}


int kMP(string a,string b){
    int i=0,j=0;
    while(i<n&&j<m){
        if(j==-1 || s[i]==pattern[j]){
            i++;
            j++;
        }
        else{
            j=next[j];
        }
    }
    if(j==m){
        return i-j+1;
    }
    else{
        //匹配失败
        return -1;
    }
}

坠落的蚂蚁

贪心

#include <bits/stdc++.h>
#include <vector>
using namespace std;

using ant = struct node{
    int pos;
    int v;
};
ant ants[1001];
int main() {
    int n;
    cin>>n;
    int target;
    int time=0;
    for(int i=0;i<n;i++){
        cin>>ants[i].pos>>ants[i].v;
        if(ants[i].v==0){
            target=i;
        }
    }
    vector<int> antsL;
    vector<int> antsR;
    
    for(int i=0;i<n;i++){
        if(i!=target){
            if(ants[i].pos>ants[target].pos && ants[i].v<0){
                antsR.push_back(ants[i].pos);
            }
            else if(ants[i].pos<ants[target].pos && ants[i].v>0){
                 antsL.push_back(ants[i].pos);
            }
        }
        
    }
    sort(antsL.begin(),antsL.end());
    sort(antsR.begin(),antsR.end());
    int l=antsL.size();
    int r=antsR.size();
    if(l==r) cout<<"Cannot fall!"<<endl;
    else if(l>r){
        // 抵消r个就够了,从后往前抵消
        cout<<100-antsL[l-r-1]<<endl;
    }
    else{
        // 从前往后抵消
        cout<<antsR[l]<<endl;
    }
    

}

棋盘游戏

给出起始坐标和终点坐标,DFS遍历图

bool st[10][10];
int a,b,c,d;
int ans=1e8;
int matrix[10][10];
int direct1[4]={1,-1,0,0};
int direct2[4]={0,0,-1,1};
void dfs(int x,int y,int cost,int status){
    if(x==c && y==d){
        ans=min(ans,cost);
        return ;
    }
    else{
        for(int i=0;i<4;i++){
                int x1=x+direct1[i];
                int y1=y+direct2[i];
                if(x1>=0 && y1>=0 && x1<=5 && y1<=5 &&  !st[x1][y1]  ){
                    st[x][y]=true;
                    int Acost=matrix[x1][y1]*status;
                    dfs(x1,y1,cost+Acost,(Acost%4)+1);
                    st[x][y]=false;
                }
        }

    }
}

快速排序

//划分
int Partition(int a[],int L,int R){
    int pivot,i=L,j=R;
    pivot=a[L];
    while(i<j){
        // 先j--再i++,保证最后a[i]<a[L]
        while(i<j && a[j]>pivot) j--;
        while(i<j && a[i]<=pivot) i++; 
        if(i<j) swap(a[i],a[j]);
    }
    //因为一定有a[i]<a[L],所以交换L和i位置的值
    swap(a[L],a[i]);
    return i;

}

//快排
void Qsort(int a[],int L,int R){
    if(L>=R) return ;
    int i=Partition(a,L,R);
    Qsort(a,L,i-1);
    Qsort(a,i+1,R);
}


选择排序

每轮选出最小的交换

for(int i=0;i<n;i++){
    int min_tmp=a[i];
    int min_index=i;
    for(int j=i+1;j<5;j++){
        if(min_tmp>a[j]){
            min_tmp=a[j];
            min_index=j;
        }
    }
    swap(a[i],a[min_index]);
}

冒泡排序

相邻的交换,每轮选出一个最大的

for(int i=0;i<n;i++){
    bool is_swap=false;
    for(int j=0;j<n-i-1;j++){
        if(a[j]>a[j+1]){
            swap(a[j],a[j+1]);
            is_swap=true;
        }
    }
    //如果本轮没有交换,说明已经是有序了
    if(!is_swap)break;
}

插入排序

插入前面已经排序好的序列

for(int i=1;i<n;i++){
    int key=a[i];
    int j=i-1;
    while(j>=0 && key<a[j]){
        a[j+1]=a[j];
        j--;
    }
    a[j+1]=key;
}

遍历建立二叉树

TNode(char c):data©,left(nullptr),right(nullptr){};

using TreeNode = struct TNode{
	char data;
	struct TNode* left;
	struct TNode* right;
	TNode(char c):data(c),left(nullptr),right(nullptr){};
};

TreeNode* Build(TreeNode* root,char c){
    
	if(c=='#')return NULL;
//	C style:(TreeNode*)malloc(sizeof(TreeNode))
	root=new TNode(c);
	char c1=s[cnt++];
	root->left=Build(root->left,c1);
	char c2=s[cnt++];
	root->right=Build(root->right,c2);
	
	return root;
}

void Inorder(TreeNode* root){
	if(root->left)
	Inorder(root->left);
	cout<<root->data<<endl;
	if(root->right)
	Inorder(root->right);
	
}
void postOrder(TreeNode* root){
	
}


int main(int argc, char** argv) {
	TreeNode* T=NULL;
	T=Build(T,s[cnt++]);
	Inorder(T);
	
	return 0;
}

中缀表达式求值

不带括号版

stack<double> nums;
stack<char> ops;

for (int i = 0; i < s.size(); i++) {
    if (isdigit(s[i])) {
        //处理10以上的数字
        if( i!=0 && isdigit(s[i-1])){
            double x=nums.top();
            nums.pop();
            nums.push(x*10+(s[i]-'0'));
        }
        else{
            nums.push(s[i]-'0');
        }
    } else {
        if (ops.empty()) {
            ops.push(s[i]);
        } else {
			//栈内符号优先级 大于等于 当前符号,则弹出  -getPriority判断符号优先级
            while (!ops.empty() &&  getPriority(s[i]) <= getPriority(ops.top())) {
                char c=ops.top();
                ops.pop();
                double a = nums.top();
                nums.pop();
                double b = nums.top();
                nums.pop();
                if (c == '*')
                    nums.push(b * a);
                else if (c == '/')
                    nums.push(b / a);
                else if (c == '+')
                    nums.push(b + a);
                else if (c == '-')
                    nums.push(b - a);
            }
            ops.push(s[i]);
        }
    }
}

while(!ops.empty()){
    char c = ops.top();
    ops.pop();

    double a = nums.top();
    nums.pop();
    double b = nums.top();
    nums.pop();

    if (c == '*')
        nums.push(b * a);
    else if (c == '/')
        nums.push(b / a);
    else if (c == '+')
        nums.push(b + a);
    else if (c == '-')
        nums.push(b - a);
}


cout << nums.top() << endl;

求最小生成树Kruskal

//1.对边排序
//2.选最小边
for(int i=0;i<n;i++){
	int a=edge[i].a;
    int b=edge[i].b;
    int w=edge[i].w;
    if(find(a)!=find(b)){
        ans+=w;
    	union(a,b);
    }
}
  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值