【机试】2011-2020年复旦大学考研复试机试真题

题型分布目录

  • 一、DP问题
    • 【2011-1】DP-最长公共子序列LCS
    • 【2014-2】DP-字符串的编辑距离
    • 【2014-4】DP-Hanoi 塔
    • 【2016-1】DP-求最大连续公共字串长度
    • 【2018-3】DP-斐波那契数列
    • 【2019-2】DP-最大连续子序列和
  • 二、二叉树问题
    • 【2011-2】中序与后序求层次遍历
    • 【2012-2】二叉树最大叶子间距
    • 【2014-3】二叉树前中后序遍历
    • 【2019-3】二叉树的形态数
  • 三、栈或队列问题
    • 【2015-3】优先队列
    • 【2016-2】后缀序列求值
    • 【2016-3】字符串的哈夫曼编码最短长度
  • 四、图
    • 【2013-3】图的BFS遍历
  • 五、查找
    • 【2014-1】二分查找
  • 六、堆排序
    • 【2012-1】1000名求前30%
  • 七、基础题(水题)
    • 【2012-3】字符串的重复输出
    • 【2013-1】字符串匹配
    • 【2013-2】A Famous ICPC Team
    • 【2015-1】长方形中的正方形
    • 【2015-2】a与b得到c
    • 【2016-1】求最大公共字串长度
    • 【2017-1】中位数
    • 【2017-2】9位ISBN,求其校验位
    • 【2018-1】求众数
    • 【2018-2】解一元一次方程
    • 【2019-1】日期处理
  • 八、补充2020年机试题
    • A、斗牛
    • B、打地鼠
    • C、排队打饭
    • D、二叉搜索树
    • E、序列

一、DP问题

【2011-1】DP-最长公共子序列LCS

问题描述:输入3个子串, 输出这3个子串的最大公共子串
输入:
abcd acb abc
输出:
ab

注意:
(1)输入的字符数组以及dp数组应定义在main函数以外(全局)
(2)由于题意求的是公共字符串,而非字符串长度,因此dp数组应为string类型

#include 
#include 
#include 
#include 
using namespace std;
const int maxn=35;
char a[maxn],b[maxn],c[maxn];
string dp[maxn][maxn][maxn];    //易错点
int main(){
	cin>>(a+1)>>(b+1)>>(c+1);
	int len1=strlen(a+1);
	int len2=strlen(b+1);
	int len3=strlen(c+1);
    //边界
	for(int i=0;i<=len1;i++){
		for(int j=0;j<=len2;j++){
			for(int k=0;k<=len3;k++){
			    dp[i][j][0]="";
				dp[i][0][k]="";
				dp[0][j][k]="";
			}
		}
	}
	//状态转移方程
	for(int i=1;i<=len1;i++){
		for(int j=1;j<=len2;j++){
			for(int k=1;k<=len3;k++){
				if(a[i]==b[j]&&a[i]==c[k]){
				    dp[i][j][k]=dp[i-1][j-1][k-1]+a[i];
				}else{
					int l1=dp[i-1][j][k].length();
					int l2=dp[i][j-1][k].length();
					int l3=dp[i][j][k-1].length();
					if(l1==max(l1,max(l2,l3))){
					    dp[i][j][k]=dp[i-1][j][k];
					}else if(l2==max(l1,max(l2,l3))){
					    dp[i][j][k]=dp[i][j-1][k];
					}else{
					    dp[i][j][k]=dp[i][j][k-1];
					}
				}
			}
		}
	}
    cout<<dp[len1][len2][len3]<<endl;
	return 0;
}

【2014-2】DP-字符串的编辑距离

题目描述:
把两个字符串变成相同的三个基本操作定义如下:
1.修改一个字符(如把a 变成b)
2.增加一个字符(如abed 变成abedd)
3.删除一个字符(如jackbllog 变成jackblog)
针对于jackbllog 到jackblog 只需要删除一个或增加一个l 就可以把两个字符串变为相同。
把这种操作需要的最小次数定义为两个字符串的编辑距离L。
编写程序计算指定文件中字符串的距离。输入两个长度不超过512 字节的ASCII 字符串,在
屏幕上输出字符串的编辑距离。
输入:
Hello world!
Hello word!
输出:
1

#include 
#include 
#include 
using namespace std;
const int maxn=10010;
int dp[maxn][maxn];
string a,b;
int main(){
    getline(cin,a);
	getline(cin,b);
	int len1=a.size();
	int len2=b.size();
    //边界
	for(int i=0;i<=len1;i++){
	    dp[i][0]=i;
	}
	for(int j=0;j<=len2;j++){
	   dp[0][j]=j;
	}
	//状态转移方程
	for(int i=1;i<=len1;i++){
		for(int j=1;j<=len2;j++){
		    int flag=0;
			if(a[i-1]!=b[j-1]){
			    flag=1;
			}
			dp[i][j]=min(dp[i-1][j-1]+flag,min(dp[i-1][j]+1,dp[i][j-1]+1));
		}
	}
	cout<<dp[len1][len2]<<endl;
	return 0;
}

【2014-4】DP-Hanoi 塔

问题描述
Hanoi 塔问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64 个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。
请编写程序,把A 柱上的n 个金片,搬动到C 柱(中间可以使用B 柱),使得搬动的次数最少。输入金片的个数n(1<=n<=64),输出总搬动次数,以及最后100 次搬动。如果搬动次数小于等于100 则全部输出;每个搬动占一行,加上是这第几次搬动的数字和”:”,格式见示例。
输入:
2
输出:
3
1:A->B
2:A->C
3:B->C

#include
#include
using namespace std;
int acount=1,count=0;
void hanoi(int n,char a,char b,char c){
	if(n==1){
		if((acount-count++)<=100){
			cout<<count<<":"<<a<<"->"<<c<<endl;
		}
	}else{
	    hanoi(n-1,a,c,b);
        if((acount-count++)<=100){
			cout<<count<<":"<<a<<"->"<<c<<endl;
		}
		hanoi(n-1,b,a,c);
	}
}
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
	    acount*=2;
	}
	acount--;
	cout<<acount<<endl;
	hanoi(n,'A','B','C');
	return 0;
}

【2016-1】DP-求最大连续公共字串长度

题目描述:给定两个字符串,求最大公共字串的长度,长度小于1000
分为两种问题:要求计算连续最长字串的长度
如下按照寻找连续的字串理解
输入:
1111hello2222
1133hello444
输出:
5
注意:公共子串是连续的,如果求不连续,用算法笔记上P435的做法

#include 
#include 
#include 
#include 
using namespace std;
const int N = 1000;
int dp[N][N] = {0};
int main(){
    string A, B;
    getline(cin, A);
    getline(cin, B);
    int l1 = A.length();
    int l2 = B.length();
    int ans = 0;
    for(int i = 0; i < l1; i++){
        for(int j = 0; j < l2; j++){
            if(A[i] != B[j]){        //两个字符不同
                dp[i][j] = 0;
            }
            else if(i == 0 || j == 0){     //字符相同,而且是第一个字符
                dp[i][j] = 1;
                if(ans < 1)
                    ans = 1;
            }
            else{                          //字符相同,均不是第一个字符
                dp[i][j] = dp[i - 1][j - 1] + 1;
                if(dp[i][j] > ans){
                    ans = dp[i][j];
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

【2018-3】DP-斐波那契数列

问题描述:有2n 的地板,用12和 2*1 的骨牌进行铺地板。问共有多少种情况。结果对 999983 取余,1<=n<=10000
输入:
6
输出:
13

#include
using namespace std;
const int maxn=10010;
int dp[maxn];
int main()
{
	int n;
	cin>>n;
	dp[1]=1;
	dp[2]=2;
	for(int i=3;i<=n;i++){
	    dp[i]=dp[i-2]+dp[i-1]%999983;
	}
	cout<<dp[n]<<endl;
	return 0;
}

【2019-2】DP-最大连续子序列和

题目描述:给定一个数组及其大小,数组元素在[-106,106],元素个数最多 10^6 个。输出最大的连续子序列和,题目保证最后结果为正数。

#include 
#include 
using namespace std;
const int maxn=1000010;
int A[maxn],dp[maxn];
int main()
{
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
	    cin>>A[i];
	}
	//边界
	dp[0]=A[0];
	for(int i=1;i<n;i++){
		//状态转移方程
	    dp[i]=max(A[i],dp[i-1]+A[i]);
	}
	int max=0;
	for(int i=0;i<n;i++){
		if(dp[i]>max){
		    max=dp[i];
		}
	}
	if(max>0)
	    cout<<max<<endl;
	else
		cout<<"No existence"<<endl;
	return 0;
}

二、二叉树问题

【2011-2】中序与后序求层次遍历

问题描述:输入树的中序和后序排列,输出树的层次遍历
输入:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出:
4 1 6 3 5 7 2

#include 
#include 
using namespace std;
struct node{
    int data;
    node* lchild;
    node* rchild;
};
int n,post[35],in[35];
node* create(int postL,int postR,int inL,int inR){       //后序和中序构造二叉树
	if(postL>postR){             
	    return NULL;
	}
	node* root=new node;
	root->data=post[postR];
	int k;
	for(k=inL;k<=inR;k++){
	    if(in[k]==post[postR])
			break;
	}
	int numleft=k-inL;
	root->lchild=create(postL,postL+numleft-1,inL,k-1);
	root->rchild=create(postL+numleft,postR-1,k+1,inR);
	return root;
}
int num=0;
void LayerOrder(node* root){     //层序遍历
    queue<node*> q;
    q.push(root);
    while(!q.empty()){
        node* now=q.front();
        q.pop();
        printf("%d",now->data);     
		num++;
		if(num<n)
			printf(" ");
        if(now->lchild!=NULL){
            q.push(now->lchild);
        }
        if(now->rchild!=NULL){
            q.push(now->rchild);
        }
    }
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
	    scanf("%d",&post[i]);
	}
	for(int i=0;i<n;i++){
	    scanf("%d",&in[i]);
	}
    node* root=create(0,n-1,0,n-1);
	LayerOrder(root);
	printf("\n");
    return 0;
}

【2012-2】二叉树最大叶子间距

问题描述:二叉树问题。比如节点是ABCDE编号是01234,给出每个左右子树的编号。求最大叶子间距。
输入1:
3
1 2
-1 -1
-1 -1
输出1:
2
输入2:
6
1 -1
2 3
4 -1
-1 5
-1 -1
-1 -1
输出2:
4

#include 
const int maxn=100;
struct node{
    int lchild,rchild;
}Node[maxn];
int maxd;  //全局变量记录最大叶子间距
//求最大叶子间距
int maxDistance(int root,int &maxd){
    if(root==-1)
		return -1;
	int lefth=maxDistance(Node[root].lchild,maxd)+1;
	int righth=maxDistance(Node[root].rchild,maxd)+1;
	if(lefth+righth>maxd){
	    maxd=lefth+righth;
	}
	return lefth>righth?lefth:righth;   //返回的是当前结点为根时的深度
}
int main(){
	int n,left,right;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
	    scanf("%d %d",&left,&right);
		Node[i].lchild=left;
		Node[i].rchild=right;
	}
    maxDistance(0,maxd);
	printf("%d\n",maxd);
    return 0;
}

【2014-3】二叉树前中后序遍历

题目描述:
输入一棵二叉树,输出树的前、中、后序遍历结果。
输入一个整数N(N<= 10000),表示树中有N个结点(编号0~N-1)。
接下来N行,依次为结点0~结点N-1的左右孩子情况。
每行3个整数,F,L,R。L,R为F的左右孩子。L,R如果为-1表示该位置上没有孩子。
分三行分别输出树的前中后序遍历。
同一行中的数字,用一个空格间隔。
输入:
5
0 3 1
1 2 -1
2 -1 4
3 -1 -1
4 -1 -1
输出:
0 3 1 2 4
3 0 2 4 1
3 4 2 1 0

#include 
const int maxn=10010;
struct node{
    int lchild,rchild;
}Node[maxn];
int n,num=0;
bool flag[maxn]={false};
void print(int id){
    printf("%d",id);
	num++;
	if(num<n)
		printf(" ");
	else
		printf("\n");
}
void preOrder(int root){
    if(root==-1)
		return;
	print(root);
	preOrder(Node[root].lchild);
	preOrder(Node[root].rchild);
}
void inOrder(int root){
    if(root==-1)
		return;
	inOrder(Node[root].lchild);
	print(root);
	inOrder(Node[root].rchild);
}
void postOrder(int root){
    if(root==-1)
		return;
	postOrder(Node[root].lchild);
	postOrder(Node[root].rchild);
	print(root);
}
int main(){
	int x,left,right;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
	    scanf("%d%d%d",&x,&left,&right);
		Node[x].lchild=left;
		Node[x].rchild=right;
		flag[left]=true;
		flag[right]=true;
	}
	int root;
	for(int i=0;i<n;i++){
		if(flag[i]==false){
		    root=i;
		}
	}
	preOrder(root);
	num=0;
	inOrder(root);
	num=0;
	postOrder(root);
    return 0;
}

【2019-3】二叉树的形态数

题目描述:给定二叉树的节点总数 n,输出二叉树形态总数,n<= 1000
输入:
3
输出:
5

#include 
long long function(int n){    //防止阶乘的结果溢出,使用long long型
	long long res;
	if(n==0)
        res=0;
	else if(n==1)
		res=1;
	else{
		res=n;
	    while(n>1){
	        res=res*(n-1);
			n--;
	    }
	}
	return res;
}
int main(){
	int n;
	long long result;
	scanf("%d",&n);
	result=function(2*n)/function(n)/function(n+1);
	printf("%lld\n",result);
    return 0;
}

三、栈或队列问题

【2015-3】优先队列

题目描述:给出优先队列的实现,实现4个操作

• ADD(N,P):往队列里加入id为N的优先级为P的任务
• NEXT:输出下一个最高优先级的任务的id,如果优先级相同输出id小的任务,若队列中没有任务输出-1
• REMOVE(N):移除id为N的任务
• COUNT:输出队列中的任务数量

#include 
#include 
#include 
#include 
#include 
using namespace std;
struct node{ 
    int id;  
	int p;   //优先级
};
struct cmp{
	bool operator()(node a,node b){
		if(a.p!=b.p)
		   return a.p<b.p;
		else
           return a.id>b.id;
	}
};
priority_queue<node,vector<node>,cmp> q;
priority_queue<node,vector<node>,cmp> temp;  //临时优先队列
void add(int id,int p){
    node a;
	a.id=id;
	a.p=p;
	q.push(a);
}
void next(){
    node a;
	a=q.top();
	cout<<a.id<<" "<<a.p;
}
void remove(int id){
	node a=q.top();
	while(a.id!=id){
	    node b=a;
		q.pop();
		temp.push(b);
	}
}
int main(){
	int id,p;
	string str;
    cin>>str;
	while(1){
		if(str=='ADD'){
            scanf("%d%d",&id,&p);
		    add(id,p);
		}else if(str=='NEXT'){
		    next();
		}else if(str=='REMOVE'){
		    scanf("%d",&id);
			remove(id);
		}else if(str=='COUNT'){
			int num=q.size();
			cout<<num<<endl;
		}else 
			break;
	}
    return 0;
}

【2016-2】后缀序列求值

题目描述:
给定一个后缀序列,要求求值,只有加减
输入:
123++4-
输出:
2

#include 
#include 
#include 
using namespace std;
stack<int> s;
int main(){
	string str;
	cin>>str;
	int k;
	for(int i=0;i<str.size();i++){
		if(str[i]>='0'&&str[i]<='9'){
		   int temp=str[i]-'0';
		   s.push(temp);
		}else if(str[i]=='+'){
			int a=s.top();
			s.pop();
			int b=s.top();
			s.pop();
            k=b+a;
			s.push(k);
		}else if(str[i]=='-'){
		    int a=s.top();
			s.pop();
			int b=s.top();
			s.pop();
            k=b-a;
			s.push(k);
		}
	}
	cout<<s.top()<<endl;
    return 0;
}

【2016-3】字符串的哈夫曼编码最短长度

题目描述:给定一个字符串(长度不超过100),求哈夫曼编码的最短长度。
输入1:
abbcccdddd
输出1:
19
输入2:
we will we will r u
输出2:
50
主要思想:优先队列+map数组+栈

#include 
#include 
#include 
#include 
#include 
using namespace std;
map<char,int> mp;
priority_queue<int,vector<int>,greater<int>> q;
string str;
int main(){
	getline(cin,str);
	int len=str.length();
	for(int i=0;i<len;i++){
		if(mp.find(str[i])==mp.end()){
		    mp[str[i]]=1;
		}else
			mp[str[i]]++;
	}
	for(map<char,int>::iterator it=mp.begin();it!=mp.end();it++){
		q.push(it->second);
	}
	int ans=0;
	while(q.size()!=1){
		int temp;
	    int a=q.top();
		q.pop();
		int b=q.top();
		q.pop();
		temp=b+a;
		ans+=temp;
		q.push(temp);
	}
	cout<<ans<<endl;
    return 0;
}

四、图

【2013-3】图的BFS遍历

题目描述:给一个表,问两个位置之间的最短距离是多少,其中素数位置不能经过。
输入:
3
1 4
9 32
10 12
输出:
Case 1: 1
Case 2: 7
Case 3: impossible

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
using namespace std;
const int maxn=410;
int g[maxn][maxn];
int vis[maxn][maxn];
const int mov[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};
bool isPrime(int v)
{
    int ed=sqrt(v);
    for(int i=2; i<=ed; ++i)
        if(v%i==0) return false;
    return true;
}
int nextDir(int d)
{
    if(d==RIGHT) return UP;
    else if(d==UP) return LEFT;
    else if(d==LEFT) return DOWN;
    else if(d==DOWN) return RIGHT;
}
pair<int,int> pos[10005];
void init()
{
 
    int val=0;
    int x=200,y=200;
    g[x][y]=++val;
    pos[val]=make_pair(x,y);
    int d=RIGHT;
    int len=2;
    while(len<=105)
    {
        for(int i=1; i<len; ++i)
        {
            x=x+mov[d][0];
            y=y+mov[d][1];
            ++val;
            if(isPrime(val)) g[x][y]=0;
            else
            {
                g[x][y]=val;
                if(val<=10000)
                    pos[val]=make_pair(x,y);
                }
        }
        d=nextDir(d);
        for(int i=1; i<len; ++i)
        {
            x=x+mov[d][0];
            y=y+mov[d][1];
            ++val;
            if(isPrime(val)) g[x][y]=0;
            else
            {
                g[x][y]=val;
                if(val<=10000)
                    pos[val]=make_pair(x,y);
                }
 
        }
        d=nextDir(d);
        ++len;
    }
 
}
 
int bfs(int st,int ed)
{
 
    memset(vis,0,sizeof(vis));
    queue<pair<int,int> > que;
    que.push(pos[st]);
    while(!que.empty())
    {
        pair<int,int> p=que.front();
        que.pop();
        for(int i=0; i<4; ++i)
        {
            int nx=p.first+mov[i][0],ny=p.second+mov[i][1];
            if(vis[nx][ny]||g[nx][ny]==0) continue;
            vis[nx][ny]=vis[p.first][p.second]+1;
            if(g[nx][ny]==ed) return vis[nx][ny];
            que.push(make_pair(nx,ny));
        }
    }
    return -1;
}
int main()
{
    init();
    int x,y,kase=0;
    while(scanf("%d%d",&x,&y)!=EOF)
    {
        printf("Case %d: ",++kase);
        if(x==y) printf("0\n");
        else
        {
            int ans=bfs(x,y);
            if(ans==-1) puts("impossible");
            else printf("%d\n",ans);
        }
    }
    return 0;
}

五、查找

【2014-1】二分查找

题目描述:大家一定都能熟练掌握二分查找啦!那么来计算二分的次数吧!约定二分的中点mid = (left + right) / 2。
输入
第一行输入一个整数N(N<=10000)。
第二行输入N个升序整数。
第三行输入一个待查找的整数(必定在第二行中出现过)。
输出
输出二分查找该整数时,进行过多少次二分。
输入:
5
18 53 54 74 99
53
输出:
2

#include
#include
using namespace std;
int count=0,input[10001];
void search(int s,int e,int key)
{
    count++;
	int mid=(s+e)/2;
	if(input[mid]==key) return;
	else if(input[mid]>key) search(s,mid,key);
	else search(mid,e,key);
}
int main()
{
	freopen("p1.in","r",stdin);
	freopen("p1.out","w",stdout);
	int N,key;
	cin>>N;
	for(int i=0;i<N;i++) cin>>input[i];
	cin>>key;
	search(0,N-1,key);
	cout<<count<<endl;
	fclose(stdin);
	fclose(stdout);
    return 0;
}

六、堆排序

【2012-1】1000名求前30%

问题描述:排序问题:1000个成绩输出前30%。
我这里输入十组数据,输出前3个
思路:
采用堆排序最佳。

#include 
#include 
using namespace std;
 //给定十个元素输出最大的前三个,元素从下标1开始存储
int heap[11] = {0, 3, 1, 2, 6, 5, 4, 9, 8, 7, 10};
int n = 10;      //元素个数
 
//对heqap数组在loe和high范围内进行调整
//low为父节点,high一般为堆的最后一个元素下标
void downAdjust(int low, int high){
    int i = low, j = i * 2;     //i为调整节点,j为左孩子
    while(j <= high){           //如果存在左孩子
        if(j + 1 <= high && heap[j + 1] > heap[j]){     //如果右孩子存在,且值大于左孩子
            j = j + 1;          //j来存储右孩子下标
        }
        //孩子中最大的权值大于要调整的节点
        if(heap[j] > heap[i]){
            swap(heap[j], heap[i]);
            i = j;          //继续调整以j为父节点的子树
            j = i * 2;
        }
        else
            break;
    }
} 
//建树
void createHeap(){
    for(int i = n / 2; i >= 1; i--){        //i从第一个非叶节点开始,直到根结点
        downAdjust(i, n);
    }
} 
void heapSort(){
    createHeap();   //建堆
    printf("%d", heap[1]);    //输出第一个最大值
    for(int i = n; i > 8; i--){     //倒着枚举,直到输出符合题目要求的数量
        swap(heap[i], heap[1]);     //交换heap[i]与堆顶
        downAdjust(1, i - 1);       //调整堆顶
        printf(" %d", heap[1]);     //调整过后,堆顶元素为最大值,输出
    }
    printf("\n");
}
 
int main(){
    heapSort();
    return 0;
}

七、基础题(水题)

【2012-3】字符串的重复输出

题目描述:给一个字符串比如ABC 再给一个整数比如3输出AAABBBCCC就行了。

#include 
#include 
#include 
using namespace std;
 
int main(){
    string str;
    getline(cin, str);
    int n;
    cin >> n;
    for(int i = 0; i < str.size(); i++){
        for(int j = 0; j < n; j++){
            printf("%c", str[i]);
        }
    }
    printf("\n");
    return 0;
}

【2013-1】字符串匹配

题目描述:对于主串M和模式串P,找到P在M中出现的所有子串的第一个字符在P中的位置。P中第一个字符所在的位置为0。首行的数字表示有多少组字符串。
输入:
2
ababababa
ababa
aaa
aa
输出:
0 2 4
0 1
(相邻位置之间用一个空格隔开)

#include
#include
#include
char str1[100],str2[100];
int main()
{
	int n;
	scanf("%d",&n);
	while(n--){
		memset(str1,0,sizeof(str1));
		memset(str2,0,sizeof(str2));
		scanf("%s",str1);
		scanf("%s",str2);
		int len1=strlen(str1);
		int len2=strlen(str2);
		int idx;
		for(int i=0;i<len1;i++){
			if(str1[i]!=str2[0])
			  continue;
			idx=i;
			if(len1-i<len2)break;
			for(int j=0;j<len2;j++){
				if(str1[i]!=str2[j])
					break;
				i++;
				if(j=len2-1)
					printf("%d ",idx);
			}
			i=idx;
		}
	}
	system("pause");
	return 0;
}

【2013-2】A Famous ICPC Team

题目描述:给出四个正方体箱子的边长,问能装下这四个正方体箱子的大正方体边长最小要多大,要求边长最小且必须能装下四个箱子。
输入:
2
2 2 2 2
输出:
4

#include 
#include 
#include 
using namespace std;
int main()
{
    int a[4],cas = 1;
    int x,y,ans;
    while(~scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3]))
    {
        sort(a,a+4);
        printf("Case %d: %d\n",cas++,a[2]+a[3]);
    }
    return 0;
}

【2015-1】长方形中的正方形

题目描述:给出长方形的长和宽,每次从长方形里撕去最大的正方形,输出最后能得到多少正方形
输入:
3 4
输出:
4

#include 
#include 
using namespace std;
 
int main(){
    int a, b;   //a 长 , b 宽
    scanf("%d%d", &a, &b);
    int ans = 0;
    while(a != b){
        ans++;
        if(a < b){
            swap(a, b);
        }
        a = a - b;
    }
    printf("%d", ans + 1);
    return 0;
}

【2015-2】a与b得到c

题目描述:给出a,b,c(3个整数),判断a,b能否通过±*/得到c,ab可以交换位置,可以输出YES,不行输出NO
输入:
3 8 2
输出:
NO

#include 
int main(){
    long long a, b, c;
    scanf("%lld%lld%lld", &a, &b, &c);
    if(a + b == c || a * b == c){
        printf("YES\n");
    }
    else if(a - b == c || b - a == c){
        printf("YES\n");
    }
    else if(a / b == c  || b / a == c){
        printf("YES\n");
    }
    else{
        printf("NO\n");
    }
    return 0;
}

【2016-1】求最大公共字串长度

题目描述:给定两个字符串,求最大公共字串的长度,长度小于1000
分为两种问题:要求计算连续最长字串的长度
如下按照寻找连续的字串理解
输入:
1111hello2222
1133hello444
输出:
5

#include 
#include 
#include 
#include 
using namespace std;
const int N = 1000;
int dp[N][N] = {0};
 
int main(){
    string A, B;
    getline(cin, A);
    getline(cin, B);
    int l1 = A.length();
    int l2 = B.length();
    int ans = 0;
    for(int i = 0; i < l1; i++){
        for(int j = 0; j < l2; j++){
            if(A[i] != B[j]){        //两个字符不同
                dp[i][j] = 0;
            }
            else if(i == 0 || j == 0){     //字符相同,而且是第一个字符
                dp[i][j] = 1;
                if(ans < 1)
                    ans = 1;
            }
            else{                          //字符相同,均不是第一个字符
                dp[i][j] = dp[i - 1][j - 1] + 1;
                if(dp[i][j] > ans){
                    ans = dp[i][j];
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}

【2017-1】中位数

题目描述:给定一个整数序列,求中位数。如果序列个数为奇数,中位数为升序的中间位置,如果是偶数,这位升序的中间两个数的平均值。
输入
输入包含多组测试数据,每一组第一行为n(n<104)表示这个序列的个数,接下来有n个整数k(031-1)
输出
输出这个序列的中位数
输入1:
5
2 1 4 3 5
输出1:
3
输入2:
4
1 4 3 2
输出2:
3

#include 
#include 
using namespace std;
const int N = 10010;
int num[N];
 
int main(){
    int n;
    scanf("%d", &n);
    for(int i =  0; i < n; i++){
        scanf("%d", &num[i]);
    }
    sort(num, num + n);
    if(n % 2 == 0){     //n为偶数
        if((num[n / 2] + num[n / 2 - 1]) % 2 == 0){     //中间两位平均值为整数
            printf("%d\n", (num[n / 2] + num[n / 2 - 1]) / 2);
        }
        else{
            printf("%.lf\n", (num[n / 2] + num[n / 2 - 1]) / 2.0);
        }
    }
    else{       //n为奇数
        printf("%d\n", num[n / 2]);
    }
    return 0;
}

【2017-2】9位ISBN,求其校验位

题目描述:给定一个9位数字的ISBN,求其校验位。ISBN格式为2-02-033598,校验位的计算方法如下:从左到右依次将各位数字乘10,9,8,……,2,求出其和S,作模运算得M=S mod 11。若11-M在1和9之间,校验位即为该数字;若11-M等于10,校验位为X;11-M等于11,校验位为0。输出添加校验位的ISBN,如2-02-033598-0。
输入1:
2-02-033598
输出1:
2-02-033598-0
输入2:
7-309-04547
输出2:
7-309-04547-5

#include 
#include 
char str[15];
int a[10];
 
int main(){
    scanf("%s", str);
    int count = 0;
    for(int i = 0; i < 11; i++){
        if(str[i] != '-'){
            a[count++] = str[i] - '0';
        }
    }
    int s = 0;
    int d = 10;
    for(int i = 0; i < 9; i++){
        s += a[i] * d;
        --d;
    }
    int m = s % 11;
    int t = 11 - m;
    if(t < 10){
        printf("%s-%d\n", str, t);
    }
    else if(t == 10){
        printf("%s-X\n", str);
    }
    else{
        printf("%s-0\n", str);
    }
    return 0;
}

【2018-1】求众数

题目描述:众数就是一个序列中出现次数最多的数字。 如果不唯一,则输出小的那个值。
样例输入:
第一行给出N(1<=n<=10^5 ),第二行给出N个数字,每个数字在int范围内
输入1:
8
10 3 8 8 3 2 2 2
输出1:
2
输入2:
5
3 3 2 4 2
输出2:
2

#include 
#include 
#include 
using namespace std;
map<int, int> mp;
 
int main(){
    int n, x;
    int maxn = 0;
    int maxp;
    scanf("%d", &n);
    for(int i = 0; i < n; i++){
        scanf("%d", &x);
        if(mp.find(x) != mp.end()){     //这个数已经出现过
            mp[x]++;
        }
        else{
            mp[x] = 1;
        }
    }
    for(map<int, int>::iterator it = mp.begin(); it != mp.end(); it++){
        if(it->second > maxn){      //已经从小到大排好序,取>即可
            maxn = it->second;      //众数出现的次数
            maxp = it->first;       //众数的值
        }
    }
    printf("%d", maxp);

【2018-2】解一元一次方程

题目描述:解方程,给定一个字符串,代表一个一元一次方程。如果有解求解,输出格式“x=数字“,如果解的个数无穷,输出 “infinite solutions”。如果没有解输出“no solution”,字符串长度不超过 256 。
输入:
2x+4-3x=x-2
输出:
x=2

#include 
#include 
#include 
using namespace std;
string str;
 
int main(){
    cin >> str;
    int a = 0, b = 0;   //系数、常数
    int sym = 1, flag = 1;      //sym表示数字之前的符号,flag表示等号的左右(初始值为1,表示在左面)
    int i = 0;          //访问字符串的下标
    while(i < str.size()){
        if(str[i] == '='){
            sym = 1;
            flag = -1;
        }
        else if(str[i] == '+'){
            sym = 1;
        }
        else if(str[i] == '-'){
            sym = -1;
        }
        else{       //遇到数字或者x
            int t = 0;      //暂存遇到的数字值
            while(i < str.size() && str[i] >= '0' && str[i] <= '9'){    //遇到数字,计算数值
                t = 10 * t + (str[i] - '0');
                ++i;
            }
            //当表达式最后一位是数字时,比如2x+4-3x=x-2,上面while的循环会使i >= str.size()成立
            if(i >= str.size()){                
                b -= t * sym;
                break;
            }
            if(str[i] == 'x' && t == 0){        //如果x之前的系数为正负1时,要单独判断,因为此时t=0
                a += sym * flag;
            }
            else if(str[i] == 'x'){     //处理系数
                a += t * sym * flag;
            }
            else{                       //处理常数
                b += t * sym * flag;
                continue;               //直接进行下一次循环是因为:上面while循环中处理数字之后已经++i
            }
        }
        i++;
    }
    if(a == 0 && b == 0){
        printf("infinite solutions\n");
    }
    else if(a != 0 && b % a == 0){
        printf("x=%d\n", -b/a);
    }
    else{
        printf("no solution\n");
    }
    return 0;
}

【2019-1】日期处理

题目描述:输入日期格式:YYYYMMDD,求与20190205的相隔的天数。
输入:20190208
输出:3

#include 
#include 
#include 
using namespace std;
 
//month[2][0]平年, month[2][1]闰年
int month[13][2] = {{0,0}, {31, 31}, {28,29}, {31,31}, {30,30}, {31, 31}, {30,30},{31, 31}, {31, 31}, {30,30}, {31, 31},{30,30},{31, 31}} ;
 
bool isLeapYear(int year){
    if(year % 400 == 0 || (year % 4 == 0  && year % 100 != 0)){
        return true;
    }
    return false;
}
 
int main(){
    int time1, time2 = 20190205;
    scanf("%d", &time1);
    if(time1 > time2){
        swap(time1, time2);
    }
    int y1, m1, d1, y2, m2, d2;
    y1 = time1 / 10000, m1 = time1 % 10000 / 100, d1 = time1 % 100;
    y2 = time2 / 10000, m2 = time2 % 10000 / 100, d2 = time2 % 100;
    int num = 0;
    while(y1 < y2 || m1 < m2 || d1 < d2){
        d1++;
        num++;
        if(d1 == month[m1][isLeapYear(y1)] + 1){
            m1++;
            d1 = 1;
        }
        if(m1 == 13){
            y1++;
            m1 = 1;
        }
    }
    cout << num << endl;
    return 0;
}

八、补充2020年机试题

A、斗牛

题目描述:给定五个 0~9 范围内的整数 a1, a2, a3, a4, a5。如果能从五个整数中选出三个并且这三个整数的和为10 的倍数(包括 0),那么这五个整数的权值即为剩下两个没被选出来的整数的和对 10 取余的结果,显然如果有多个三元组满⾜和是 10 的倍数,剩下两个数之和对 10 取余的结果都是相同的;如果
选不出这样三个整数,则这五个整数的权值为 -1。
现在给定 T 组数据,每组数据包含五个 0~9 范围内的整数,分别求这 T 组数据中五个整数的权值。
【输入格式】 第一行一个整数 T (1<=T<=1000),表⽰数据组数。 接下来 T 行,每行 5 个 0~9 的整数,表示一组数据。
【输出格式】输出 T 行,每行一个整数,表⽰每组数据中五个整数的权值。

#include 
#include 
#include 
using namespace std;

//回溯法得到其中三数之和,若没有10的倍数,返回-1
int judge(int sum,vector<int>& visited,vector<int>D,int num) {
	if (num > 3)	return -1;
	if (num == 3 && sum % 10 == 0)	return sum;
	for (int i = 0; i < D.size(); i++) {
		if (visited[i] == 0) {
			visited[i] = 1;
			int f = judge(sum + D[i], visited, D, num + 1);
			if (f != -1)	return f;
			visited[i] = 0;
		}
	}
	return -1;
}

int main()
{
	int T;
	cin >> T;
	int N = 5;
	vector<vector<int>>data(T, vector<int>(N));
	for (int i = 0; i < T; i++) {
		for (int j = 0; j < N; j++) {
			cin >> data[i][j];
		}
	}
	vector<int>result;
	vector<int> visited(N, 0);	//记录已被访问过的数
	for (int i = 0; i < T; i++) {
		int sum = 0, num = 0;
		fill(visited.begin(), visited.end(), 0);
		int flag = judge(sum, visited, data[i], num);
		if (flag != -1) {	//存在三数之和为10的倍数
			int S = 0;
			for (int j = 0; j < N; j++)	S += data[i][j];
			result.push_back((S - flag) % 10);	//总和减去三数之和就是剩余两数之和
		}
		else  result.push_back(flag);
	}
	for (int i = 0; i < result.size(); i++)	cout << result[i] << endl;
}

B、打地鼠

题目描述:给定 n 个整数 a1, a2, …, an 和⼀个 d,你需要选出若⼲个整数,使得将这些整数从⼩到⼤排好序之后,任意两个相邻的数之差都不⼩于给定的 d,问最多能选多少个数出来。
【输⼊格式】 第⼀⾏两个整数 n,d (1<=n<=10^5, 0<=d<=10^9),分别表⽰整数个数和相邻整数差的下界。 第⼆⾏ n
个整数 a1, a2, …, an (1<=ai<=10^9, 1<=i<=n),表⽰给定的 n 个整数。
【输出格式】 仅⼀⾏⼀个整数,表⽰答案。

#include 
#include 
#include 
using namespace std;
int main()
{
	int n, d;
	cin >> n >> d;
	vector<int>data(n);
	for (int i = 0; i < data.size(); i++)	cin >> data[i];
	sort(data.begin(), data.end());	//从小到大排序
	int num = 0;
	if (n < 2) {	//只有一个整数
		cout << num << endl;
		return 0;
	}

	for (int i = 0, j = 1; j < data.size();) {
		if (data[j] - data[i] >= d) {
			num++;
			i = j;
			j++;
		}
		else j++;
	}
	if (num == 0)	cout << num << endl;	//没有符合条件的数
	else  cout << num + 1 << endl;	//由于每次只将较小的数加入结果集,因此最后还需将最后的大数加入结果集
	return 0;
}

C、排队打饭

题目描述:下课了,有 n 位同学陆续赶到⻝堂进⾏排队打饭,其中第 i 位同学的到达时间为 ai,打饭耗时为 ti,等待时间上限为 bi,即如果其在第 ai+bi 秒的时刻仍然没有轮到他开始打饭,那么他将离开打饭队列,另寻吃饭的地⽅。问每位同学的开始打饭时间,或者指出其提前离开了队伍(如果这样则输出 -1)。
【输⼊格式】 第一行一个整数 n (1<=n<=105),表⽰来打饭的同学数量。 接下来 n行,每⾏三个整数 ai,ti,bi (1<=ai,ti,bi<=10^9, 1<=i<=n),分别表⽰每位同学的到达时间、打 饭耗时、等待时间上限。 保证 a1 【输出格式】 一行n 个整数,表⽰每位同学的开始打饭时间或者 -1(如果该同学提前离开了队伍)。

#include 
#include 
#include 
using namespace std;
int main()
{
	int n;
	cin >> n;
	vector<vector<long long int>>data(n, vector<long long int>(3));
	for (int i = 0; i < data.size(); i++){
		for (int j = 0; j < data[i].size(); j++) {
			cin >> data[i][j];
		}
	}
	long long int endtime = 0;	//记录上一个学生打饭结束的时间
	vector<long long int>result;
	for (int i = 0; i < data.size(); i++) {
		if (data[i][0] >= endtime) {	//第i位学生达到时无人打饭,可以直接开始打饭
			result.push_back(data[i][0]);
			endtime = data[i][0] + data[i][1];
		}
		else {	//第i位学生正好有人打饭,那么第i位学生的等待时间=上一位学生的结束时间-第i位学生的开始时间
			if (endtime - data[i][0] > data[i][2])	result.push_back(-1);	
			else {
				result.push_back(endtime);
				endtime = endtime + data[i][1];
			}
		}
	}
	for (int i = 0; i < result.size(); i++)	cout << result[i] << ' ';
	return 0;
}

D、二叉搜索树

题目描述:给定⼀个 1-n 的排列 P,即⻓度为 n,且 1~n 中所有数字都恰好出现⼀次的序列。现在按顺序将排列中的元素⼀⼀插⼊到初始为空的⼆叉搜索树中(左小右大),问最后每个节点的⽗亲节点的元素是什么。特别地,根节点的⽗亲节点元素视为 0。
【输⼊格式】
第⼀⾏⼀个整数 n (1<=n<=10^5),表⽰排列 P 中的元素个数。
第⼆⾏ n 个整数 p1, p2, …, pn (1<=pi<=n, 1<=i<=n),表⽰给定的排列。
【输出格式】 ⼀⾏ n 个整数,其中第 i 个整数 ai 表⽰元素 i 对应节点的⽗亲节点的元素。特别地,根节点的⽗亲节 点元素视为 0。

#include 
#include 
#include 
#include 
using namespace std;
int main(){
int n;
	cin >> n;
	vector<int>father(n + 1);
	map<int, int>dict;
	dict[0] = 0;
	int maxn = 0;
	for (int i = 0; i < n; i++) {
		int t;
		cin >> t;
		if (t > maxn) {
			father[t] = maxn;
			dict[t] = dict[maxn] + 1;
			maxn = t;
		}
		else {
			map<int, int>::iterator small = dict.upper_bound(t);
			map<int, int>::iterator big = small--;
			if (big->second > small->second) {
				father[t] = big->first;
				dict[t] = big->second + 1;
			}
			else {
				father[t] = small->first;
				dict[t] = small->second + 1;
			}
		}
	}
	for (int i = 1; i < father.size(); i++)	cout << father[i] << ' ';
}

E、序列

题目描述:给定⼀个⻓为 n 的序列 A,其中序列中的元素都是 0~9 之间的整数,对于⼀个⻓度同样为 n 整数序列B,定义其权值为 |A_i-B_i| (1<=i<=n) 之和加上 (B_j-B_j+1)^2 (1<=j 【输⼊格式】 第⼀⾏⼀个整数 n (1<=n<=10^5),表⽰序列 A 的⻓度。 第⼆⾏ n 个整数 a1, a2, …, an (0<=ai<=9, 1<=i<=n),表⽰序列 A 中的元素。
【输出格式】仅⼀⾏⼀个整数,表⽰答案。

#include 
#include 
#include 
#include 
#include 
using namespace std;

#define N 10

int main() {
	int n;
	cin >> n;
	vector<int>A(n);
	for (int i = 0; i < A.size(); i++)	cin >> A[i];
	vector<vector<int>>dp(n, vector<int>(N, INT_MAX));
	for (int i = 0; i < N; i++)	dp[0][i] = abs(i - A[0]);
	for (int i = 1; i < A.size(); i++) {
		for (int j = 0; j < N; j++) {
			for (int k = 0; k < N; k++) {
				dp[i][j] = min(dp[i][j], dp[i - 1][k] + abs(A[i] - j) + (j - k)*(j - k));
			}
		}
	}
	int result = INT_MAX;
	for (int i = 0; i < N; i++)	result = min(result, dp[n - 1][i]);
	cout << result;
	return 0;
}

温馨提示:资源整理不易,看到最后,记得一键三连奥,笔芯!!!

你可能感兴趣的:(真题,字符串,算法,leetcode,动态规划,c++)