北大2019计算机学科夏令营上机考试

目录

A:数与字符串【找规律】

B:打印月历【暴力水题】

C:Hopscotch【BFS】

D:上楼梯【动态规划】

E:Life Line 【图】

F:跳蛙【DSP】

G:Falling Leaves【二叉搜索树】

H:昂贵的聘礼【图】

I:Connect【放弃】

A:数与字符串【找规律】

#include<iostream>
#include<cstring>
using namespace std;
int flag;
char n[8],res[8];
int main(void){
    cin>>n;
    while(strcmp(n,"0")!=0){
        int len=strlen(n);
        flag=1;
        for(int i=0;i<len-1;i++){
            if(n[i]!='9') flag=0;
        }
        if(flag==1) strcpy(res,n);
        else{
            for(int i=0;i<len-1;i++){
                res[i]='9';
            }
            res[len-1]='\0';
        }
        cout<<res<<endl;
        cin>>n;
    }
}

#include<iostream>
#include<cstring>
using namespace std;
int flag;
char n[8],res[8];
int main(void){
	cin>>n;
	while(strcmp(n,"0")!=0){
		int len=strlen(n);
		flag=1;
		
		for(int i=0;i<len-1;i++){
			if(n[i]!='9') flag=0;
		}
		if(flag==1)  cout<<n;
		for(int i=0;i<len-1;i++) cout<<"9";	

		cout<<endl;
		cin>>n;
	}
}

B:打印月历【暴力水题】

#include<iostream>
using namespace std;
int year,month;

int main(){
    cin>>year>>month;
    cout<<"Sun Mon Tue Wed Thu Fri Sat"<<endl;
    if((year%4==0&&year%100!=0)||(year%400==0))//闰年 
    { 
        if(month==2) cout<<"      1   2   3   4   5   6"<<endl
 <<"  7   8   9  10  11  12  13"<<endl
 <<" 14  15  16  17  18  19  20"<<endl
 <<" 21  22  23  24  25  26  27"<<endl
 <<" 28  29";    
    if(month==2) cout<<"      1   2   3   4   5   6"<<endl
 <<"  7   8   9  10  11  12  13"<<endl
 <<" 14  15  16  17  18  19  20"<<endl
 <<" 21  22  23  24  25  26  27"<<endl
 <<" 28";    
    }
    if(month==1||month==3||month==5||month==7||month==8||month==10||month==12) 
            cout<<"      1   2   3   4   5   6"<<endl
 <<"  7   8   9  10  11  12  13"<<endl
 <<" 14  15  16  17  18  19  20"<<endl
 <<" 21  22  23  24  25  26  27"<<endl
 <<" 28  29  30  31";    
       if(month==4||month==6||month==9||month==11)
           cout<<"      1   2   3   4   5   6"<<endl
 <<"  7   8   9  10  11  12  13"<<endl
 <<" 14  15  16  17  18  19  20"<<endl
 <<" 21  22  23  24  25  26  27"<<endl
 <<" 28  29  30";
    return 0; 
}
 

C:Hopscotch【BFS】

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

typedef struct house
{
	int data;
	string str;
}house;

char a[100000];
int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		if(m==0&&n==0) return 0;
		if(m==n)
		{
			cout<<"0"; 
			break;
		}
    	memset(a,0,sizeof(a));
		/*格子初始化*/
		house h;
		h.data = n;
		h.str = "";
		
		queue<house> q;//遍历的辅助队列 
		q.push(h);

		while(!q.empty())
		{
			/*队首出队*/
			house Front = q.front();
			q.pop();
			
			/*第一种情况*/
			house now;
			now.data = Front.data * 3;
			now.str = Front.str + "H";
			if(now.data==m)//达到目标,停止搜索 
			{
				cout<<now.str.length()<<endl<<now.str<<endl;
				break;
			}
			if(a[now.data]==0)//检查之前有没有得过这个结果(剪枝) 
			{
				q.push(now);
				a[now.data] = 1;
			}
			
			
			/*第二种情况*/
			now.data = Front.data / 2;
			now.str = Front.str + "O";
			if(now.data==m)//同上
			{
				cout<<now.str.length()<<endl<<now.str<<endl;
				break;
			} 
			if(now.data!=0 && a[now.data]==0)//如果为0或者之前访问过了,那么剪枝(不入队) 
			{
				q.push(now);
			}
		}
	}
	return 0;
}

没有可以提交的地方,但是测了几组数据都通过啦!

D:上楼梯【动态规划】

 (1条消息) 【POJ】2019计算机学科夏令营上机考试 D:上楼梯_Star Kirby的博客-CSDN博客

(1条消息) 告别动态规划,连刷40道动规算法题,我总结了动规的套路_Hollis Chuang的博客-CSDN博客

上面这个动态规划讲得很好,看一遍基本就能明白了,剩下就是做题

#include<cstdio>
typedef long long ll;
bool contain(int x){
	int temp;
	while(x){
		temp = x%4;
		if(temp==4) return true;
		x/=10;
	}
	return false;
}
ll f(int n,int k){
	ll bp[60];
	bp[0] = 1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=k&&j<=i;j++)
			if (j%10 ==4 || j/10==4) //不吉利 
				continue;
			else
				bp[i] += bp[i-j];
	return bp[n];
}
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	while(n!=0&&k!=0){
		printf("%lld\n",f(n,k));
		scanf("%d%d",&n,&k);
	}
	return 0;
}

①找到动态规划的目标数组(一定要搞清楚数组的具体含义)

②找到递推关系,一般就是这一步的状态是由什么得到的

③初始化数值!!!!!!很重要!!!特别是0的时候!!!

E:Life Line 【图】

参考:1414:Life Line【2019北大夏令营E】

#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <climits>

using namespace std;
#define MAXNODE 60
#define MAXN 12
int chess[MAXNODE];
struct Comp
{
    int node_num;
    int empty_nbr_num;
    Comp(int n0,int e0):node_num(n0),empty_nbr_num(e0){}
};
void insert_edge(unordered_map<int,vector<int>>&nbrs, unordered_map<int,vector<int>>&empty_enbrs,int node_id, int l)
{
    nbrs[node_id].push_back(l);
    nbrs[l].push_back(node_id);
    if(chess[node_id]==0 && chess[l]==0){
        empty_enbrs[node_id].push_back(l);
        empty_enbrs[l].push_back(node_id);
    }
}
int main()
{
    int N,C;
    int node_id;
    while(cin>>N>>C && (N||C)){
        node_id=0;
        vector<int>empty_node;
        int c;
        unordered_map<int,vector<int>>nbrs;
        unordered_map<int,vector<int>>empty_enbrs;
        for(int i=0; i<N; ++i){
            for(int j=0; j<=i; ++j){
                cin>>c;
                if(c==0){
                    empty_node.push_back(node_id);
                }
                chess[node_id++]=c;
            }
        }
        int tmp=0;
        for(int i=0; i<N-1; ++i){
            for(int j=0; j<=i; ++j){
                //triangle: tmp tmp+i+1 tmp+i+2
                int l=tmp+i+1;
                int r=tmp+i+2;
                insert_edge(nbrs,empty_enbrs,tmp,l);
                insert_edge(nbrs,empty_enbrs,tmp,r);
                insert_edge(nbrs,empty_enbrs,r,l);
                ++tmp;
            }
        }

       
        unordered_map<int,vector<Comp>> empty2comps,empty2Ccomps;
        int comp_sz;
        unordered_set<int>empty_nbrs;
        //bfs for comp
        int visited[MAXNODE]={0};//mark when pushing into queue(one node might be the same neighbor of different nodes)
        for(int i=0; i<node_id; ++i){
            if(visited[i]==0 && chess[i]){
                comp_sz=0;
                empty_nbrs.clear();
                //bfs
                c=chess[i];
                queue<int>q;
                q.push(i);visited[i]=1;
                int curr;
                while(q.empty()==0){
                    curr=q.front();q.pop();
                    ++comp_sz;
                    for(int nbr:nbrs[curr]){
                        if(chess[nbr]==0){
                            empty_nbrs.insert(nbr);
                        }
                        if(chess[nbr]==c && visited[nbr]==0){
                            q.push(nbr);
                            visited[nbr]=1;
                        }
                    }
                }
                int empty_nbrs_sz=empty_nbrs.size();
                if(c==C){
                    for(int e:empty_nbrs){
                        empty2Ccomps[e].emplace_back(comp_sz,empty_nbrs_sz);
                    }
                }else{
                    if(empty_nbrs_sz<=1){
                        for(int e:empty_nbrs){
                            empty2comps[e].emplace_back(comp_sz,empty_nbrs_sz);
                        }
                    }
                }
            }
        }

        int max_score=INT_MIN;
        for(int e:empty_node){
            //cout<<"empty:"<<e<<" "<<chess[e]<<endl;
            int score=0;
            //add
            for(Comp cp:empty2comps[e]){
                score+=cp.node_num;
            }
            //del
            int del_score=0;
            //check whether has other empty nbr besides e
            //note this added stone's empty nbr need to considered
            bool has_other_nbr=(empty_enbrs[e].size()>0);
            for(Comp cp:empty2Ccomps[e]){
                del_score+=cp.node_num;
                if(cp.empty_nbr_num>1){
                    has_other_nbr=1;
                }
            }
            if(has_other_nbr==0){//after connect, no empty nbr
                score-=del_score;
                --score;
            }
            //cout<<"score:"<<score<<endl;
            if(score>max_score){
                max_score=score;
            }
        }
        cout<<max_score<<endl;
    }
    return 0;
}

POJ平台可以测试:POJ平台链接

F:跳蛙【DSP】

//http://bailian.openjudge.cn/xly2019/F/
#define MAX_STATE 1100
int visited[MAX_STATE]={0};
//idx from 1
int n;
bool solve(int lf, int rf, int start){
    if(start==n){
        return 1;
    }
    if(visited[lf*100+start]) return 0;
    visited[lf*100+start]=1;
    //left
    if(start-lf>1){
        for(int i=1; i<=lf; ++i){
            if(solve(lf-i, rf+i, start-i-1)){
                return 1;
            }
        }
    }
    //right
    if(start+rf<n){
        for(int i=1; i<=rf; ++i){
            if(solve(lf+i, rf-i, start+i+1)){
                return 1;
            }
        }
    }
    //no solution
    return 0;
}

int main(){
    while(cin>>n && n){
        int lf=0,rf=0;
        char c;
        for(int i=0; i<n; ++i){
            cin>>c;
            if(c=='B') ++rf; 
        }
        if(solve(lf,rf,1)) cout<<"Y"<<endl;
        else cout<<"N"<<endl;
    }
    return 0;
}


/*
char map[10];
dfs(int x){  //x表示青蛙王当前的位置 
	if(x>=n) cout<<Y<<endl;
	if(map[x+1]=="N"&&map[x+2]==".") {
		swap(map[x],map[x+2]);
		dfs(x+2);
		swap(map[x+1],map[x+2]);
		dfs(x);
	}
	if(map[x-1]=="N"&&map[x-2]==".") {
		swap(map[x],map[x-2]);
		dfs(x-2);
		swap(map[x-1],map[x-2]);
		dfs(x);
	}
}
int main(){
	int n; 
	while(cin>>n&&n){
		for(int i=0;i<n;i++){
			cin>>map[i];
		}
		dfs(0);
	} 
	return 0;
}
*/

下半部分注释掉的是用深搜错误思路做的

满足条件的时候 青蛙王和普通青蛙可以跳  但是不一定跳 这样就有三种情况,而且我找不到递归出口  他们难道不是可以一直跳跳跳跳个没完没了,总不能把所有可能的位置排列全部找出来 然后全走过一遍置为1  再return吧。 

所以上述思路行不通!

改进后的这段代码通过递归实现了判断青蛙王是否能够到达棋盘最右侧的功能。

代码中的solve函数接收三个参数:lf表示青蛙王左侧的普通青蛙数量,rf表示青蛙王右侧的普通青蛙数量,start表示当前青蛙王的位置。

首先,如果当前位置已经到达最右侧(start==n),则返回1,表示可以到达。

然后,通过visited数组判断是否访问过当前状态,避免重复计算。visited数组的大小为MAX_STATE,根据最大的状态数来定义。

接下来,针对青蛙王向左和向右移动的情况进行判断。

1. 青蛙王向左移动:如果左侧有足够的空地(start-lf>1),则遍历左侧每一只普通青蛙,将当前青蛙王的位置和普通青蛙的数量更新为移动后的位置和数量,并递归调用solve函数。如果递归调用的返回值为1,则表示可以到达,直接返回1。

2. 青蛙王向右移动:如果右侧有足够的空地(start+rf<n),则遍历右侧每一只普通青蛙,将当前青蛙王的位置和普通青蛙的数量更新为移动后的位置和数量,并递归调用solve函数。如果递归调用的返回值为1,则表示可以到达,直接返回1。

最后,如果上述情况都不满足,则返回0,表示无法到达。

在主函数中,通过循环读取输入的数据,并调用solve函数进行判断。根据solve函数的返回值,输出相应的结果。

但是但是!!!没有提交入口,只有案例跑过了,其他数据不知道!

G:Falling Leaves【二叉搜索树】

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

struct Node
{
	char data;
	Node *left;
	Node *right;
};
typedef struct Node* Tree;

string temp, str;

Tree Insert(Tree BST,char x)
{
	if(BST==NULL)
	{
		BST = (Tree)malloc(sizeof(Node));
		BST->data = x;
		BST->left=BST->right=NULL;
	}
	else{
		if(x<BST->data)//左节点 
		{
			BST->left = Insert(BST->left,x); 
		}
		else if(x>BST->data)//右节点
		{
			BST->right = Insert(BST->right,x); 
		} 
		//数据已存在的话就不插入 
	}
	return BST; 
}
Tree createBST(){  //建树
    Tree root = NULL;
    for(int i=0;i<str.length();i++)
    	root = Insert(root,str[i]);
    return root;    //返回根结点
}


void Print(Tree BST)
{
	if(BST!=NULL)
	{
		printf("%c",BST->data);
		Print(BST->left);
		Print(BST->right);
	}
}

int main(){
    while(cin >> temp){  //输入字符串
        if(temp != "*" && temp != "$"){
            //如果输入的字符串不是组结束符或结尾符
            str += temp;    //将出入的字符串加到str字符串尾部
            continue;
        }
        //如果输入的时组结束符或结尾符
        reverse(str.begin(),str.end()); //将str数组反转
        Tree bst = createBST();   //建树
        str = "";   //将str清空
        Print(bst); //输出前序遍历
        printf("\n");
        if(temp == "$")//如果是结尾符跳出循环
            break;
    }
    return 0;
}

注意点:要翻转序列!!!

在二叉搜索树中,如果叶子节点按照由小到大的顺序排列,那么在插入叶子节点时,首先要插入的是最大的叶子节点作为根节点,然后插入次大的叶子节点作为根节点的右子节点,再插入次次大的叶子节点作为右子节点的右子节点,以此类推。

而给定的输入叶子节点序列是按照由小到大的顺序排列的。为了满足上述的插入顺序,我们需要将输入的叶子节点序列反转,变成由大到小的顺序排列,这样在插入节点时就会按照正确的顺序进行。

通过调用`reverse(str.begin(),str.end())`函数,可以将字符串中的字符顺序进行反转。

在完成插入节点之后,我们再进行前序遍历,即根节点->左子树->右子树的顺序输出树中的节点值。这样,通过输入的叶子节点序列,就可以正确地构建出二叉搜索树,并按照前序遍历的顺序输出节点值。

H:昂贵的聘礼【图】

#include <iostream>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int m,n;
const int N=105;
const int INF=0x3f3f3f3f;
int price[N],level[N];
int edge[N][N];
int vis[N];
int d[N];
void init(){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            edge[i][j]=INF;
        }
    }
    for(int i=0;i<n;i++){
        cin>>price[i]>>level[i];
        level[i]--;//0开始
        int x;
        cin>>x;
        for(int j=0;j<x;j++){
            int v,p;
            cin>>v>>p;
            v--;
            edge[v][i]=p;//v到i的价格为p
        }
    }
}
int dijkstr(){
    for(int i=0;i<n;i++)d[i]=price[i];//把起点当作超级源点
    for(int i=0;i<n;i++){
        int temp=INF;
        int x;//最小点
        for(int j=0;j<n;j++)
            if(vis[j]&&d[j]<=temp)
                temp=d[x=j];
            vis[x]=0;//不再走
            for(int j=0;j<n;j++)
                if(d[x]+edge[x][j]<d[j]&&vis[j])
                    d[j]=d[x]+edge[x][j];
        }
    return d[0];//0
}
int main()
{
    cin>>m>>n;
    init();
    int ans=INF;
    for(int i=0;i<n;i++){
        int minLevel=level[i];//最小
        for(int j=0;j<n;j++){
            if(level[j]-minLevel>m||minLevel>level[j])
                vis[j]=0;//不可
            else vis[j]=1;
        }
        int cur=dijkstr();
       // cout<<cur<<endl;
        ans=min(ans,cur);
    }
    cout<<ans<<endl;
    return 0;
}

I:Connect【放弃】

不想做了 最后一个题 放弃

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值