字节跳动2018算法工程师校招编程题题解(第三批)

编程题1

题目大意

给一个二阶魔方,每块都给定一个数字,定义优美度等于每面四块乘机之和,求五步之内优美度的最大值。
魔方展开如图
在这里插入图片描述

思路

显然的dfs,模拟即可,注意魔方是如何旋转的。
三个方向分顺时针逆时针共6种情况,注意上层顺时针和下层顺时针是一样的,不用额外分情况。
复杂度O( 6 5 6^5 65)

AC代码

#include<stdio.h>
#include<string.h>
#include<vector>
#define ll long long
using namespace std;
int c[30];
int ans=-600000005;
void cal(int a[]){
    int res=0;
    res+=a[0]*a[1]*a[2]*a[3];
    res+=a[4]*a[5]*a[10]*a[11];
    res+=a[6]*a[7]*a[12]*a[13];
    res+=a[8]*a[9]*a[14]*a[15];
    res+=a[16]*a[17]*a[18]*a[19];
    res+=a[20]*a[21]*a[22]*a[23];
    ans=ans>res?ans:res;
    return ;
}
void dfs(int a[],int num){
    int b[30];
    cal(a);
    if(num==5)return ;
    for(int i=0;i<=23;i++){
        b[i]=a[i];
    }
    b[0]=a[1],b[1]=a[3],b[2]=a[0],b[3]=a[2];
    b[4]=a[23],b[5]=a[22],b[22]=a[9],b[23]=a[8];
     
    for(int i=4;i<=7;i++){
        b[i+2]=a[i];
    }
    dfs(b,num+1);
    b[0]=a[2],b[1]=a[0],b[2]=a[3],b[3]=a[1];
    b[8]=a[23],b[9]=a[22],b[22]=a[5],b[23]=a[4];
    for(int i=4;i<=7;i++){
        b[i]=a[i+2];
    }
    dfs(b,num+1);
    for(int i=0;i<=23;i++){
        b[i]=a[i];
    }
    b[1]=a[7],b[3]=a[13],b[7]=a[17],b[13]=a[19];
    b[17]=a[21],b[19]=a[23],b[21]=a[1],b[23]=a[3];
    b[8]=a[14],b[9]=a[8],b[14]=a[15],b[15]=a[9];
    dfs(b,num+1);
    b[1]=a[21],b[3]=a[23],b[7]=a[1],b[13]=a[3];
    b[17]=a[7],b[19]=a[13],b[21]=a[17],b[23]=a[19];
    b[8]=a[9],b[9]=a[15],b[14]=a[8],b[15]=a[14];   
    dfs(b,num+1);
    for(int i=0;i<=23;i++){
        b[i]=a[i];
    }
    b[2]=a[8],b[3]=a[14],b[8]=a[17],b[14]=a[16];
    b[5]=a[3],b[11]=a[2],b[16]=a[5],b[17]=a[11];
    b[6]=a[7],b[7]=a[13],b[12]=a[6],b[13]=a[12];
    dfs(b,num+1);
    b[2]=a[11],b[3]=a[5],b[8]=a[2],b[14]=a[3];
    b[5]=a[16],b[11]=a[17],b[16]=a[14],b[17]=a[8];
    b[6]=a[12],b[7]=a[6],b[12]=a[13],b[13]=a[7];
    dfs(b,num+1);
    return ;
}
int main(){
    for(int i=0;i<=23;i++){
        scanf("%d",&c[i]);
    }
    dfs(c,0);
    printf("%d",ans);
    return 0;
}

写法很丑勿喷,如果有简便写法请务必告诉我,谢谢!

编程题2

题目大意

推箱子游戏,给定人起点,箱子起点以及终点,问人推箱子到终点的最少步数,推不到输出-1 。
图如下:
在这里插入图片描述

思路

显然是bfs,但是容易会对箱子和人分别bfs,先bfs箱子下一步,然后bfs计算人在当前位置实现箱子移动的步数。存在一个严重问题,因为人要不同方向推箱子是要移动的,所以这里箱子的bfs并不是递增的,先执行的步骤步数不一定是最小的。
我们需要对箱子和人同时bfs,建立四维数组记录箱子和人的位置的vis即可。

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
char Map[55][55];
int vis[55][55][55][55];
int dir[5][5]={{0,1},{0,-1},{1,0},{-1,0}};
struct Node
{
	int x,y;
}box,person,tmpbox,tmpperson;
bool invalid(Node a){
	if(a.x<0||a.x>=n)return true;
	if(a.y<0||a.y>=m)return true;
	if(Map[a.x][a.y]=='#')return true;
	return false;
}
int bx,by,px,py,ex,ey;
queue<pair<pair<Node,Node>,int>>q;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%s",Map[i]);
		for(int j=0;j<m;j++){
			if(Map[i][j]=='0')bx=i,by=j;
			else if(Map[i][j]=='S')px=i,py=j;
			else if(Map[i][j]=='E')ex=i,ey=j;
		}
	}
	q.push({{(Node){bx,by},(Node){px,py}},0});
	vis[bx][by][px][py]=1;
	while(!q.empty()){
		box=q.front().first.first;
		person=q.front().first.second;
		int num=q.front().second;
		q.pop();
		for(int i=0;i<4;i++){
			tmpperson.x=person.x+dir[i][0];
			tmpperson.y=person.y+dir[i][1];
			if(invalid(tmpperson))continue;
			if(tmpperson.x!=box.x||tmpperson.y!=box.y){
				if(vis[box.x][box.y][tmpperson.x][tmpperson.y]==0){
					vis[box.x][box.y][tmpperson.x][tmpperson.y]=1;
					q.push({{box,tmpperson},num+1});
				}
			}
			else{
				tmpbox.x=box.x+dir[i][0];
				tmpbox.y=box.y+dir[i][1];
				if(invalid(tmpbox))continue;
				if(tmpbox.x==ex&&tmpbox.y==ey){
					printf("%d",num+1);
					return 0;
				}
				if(vis[tmpbox.x][tmpbox.y][tmpperson.x][tmpperson.y]==0){
					vis[tmpbox.x][tmpbox.y][tmpperson.x][tmpperson.y]=1;
					q.push({{tmpbox,tmpperson},num+1});
				}
			}
		}

	}
	printf("-1");
	return 0;
}  

编程题3

题目大意

有n个房间,现在i号房间里的人需要被重新分配,分配的规则是这样的:先让i号房间里的人全都出来,接下来按照 i+1, i+2, i+3, … 的顺序依此往这些房间里放一个人,n号房间的的下一个房间是1号房间,直到所有的人都被重新分配。
现在告诉你分配完后每个房间的人数以及最后一个人被分配的房间号x,你需要求出分配前每个房间的人数。数据保证一定有解,若有多解输出任意一个解。

思路

我们只需要找到一开始选的点这题就解决了,因为一开始选的点会变成0,所以可以很快得到所有房间的最小值就是一开始选的点。当有多个最小值时,我们考虑最后分配的位置。如果分配位置就是最小值,那就是以该最小值分配一圈。如果不是,那么最小值之后到最后分配点分配的人数是最小值+1,最后分配点到最小值分配的人数是最小值,所以最小值到最后分配点之间不能有等于最小值的点,所以初始点是最后分配点之前的最后一个最小值(注意这里的之前是一圈的之前)

AC代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,x,p,q;
ll a[100005];
ll mina=1e10;
int main(){
	scanf("%d%d",&n,&x);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	p=x;
	while(1){
		p++;
		if(p>n)p=1;
		if(a[p]<=mina){
			mina=a[p];
			q=p;
		}
		if(p==x)break;
	}
	if(q==x){
		for(int i=1;i<=n;i++){
			a[i]-=mina;
			a[q]+=mina;
		}
		for(int i=1;i<=n;i++){
			printf("%lld ",a[i]);
		}
		system("pause");
		return 0;
	}
	p=q;
	while(1){
		p++;
		if(p>n)p=1;
		a[p]-=mina+1;
		a[q]+=mina+1;
		if(p==x)break;
	}
	while(1){
		p++;
		if(p>n)p=1;
		if(p==q)break;
		a[p]-=mina;
		a[q]+=mina;
	}
	for(int i=1;i<=n;i++){
		printf("%lld ",a[i]);
	}
	system("pause");
	return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值