网易游戏开发岗笔试经历 2020.9.5 Apare_xzc

网易游戏开发岗笔试(2020.9.5 15:00-17:30)


昨天的笔试,做得挺难受的,当时正在搬寝室,很吵,然后保洁阿姨来打扫寝室卫生…
2.5小时,4道编程题,每道题100分。 1, 0.2 0 0.1 ,第2题应该就是模拟,说我TLE,第三题bfs,说段错误,不知道map哪里来的段错误…, 第四题就5分钟了,想到了思路,细节除了点问题,敲完就交了,剩下几秒钟结束,过了10%,j++写成了i++…


第一题:自动贩卖机

题意:

        模拟一个自动贩卖机。贩卖机有n个货物口,每个货口初始都放了无限多的相同的货物,货物的单价为a[i], 每个人通过手机扫码可以打开贩卖机的门,拿东西,然后关上门之后,贩卖机会自动扣费。现在让你实现这个计费功能。

        每个人可以从x号货物口拿一个货物到左手或者右手上,记为take left x 或者 take right x。可以把左手或者右手的货物放到y号货物口,记为return left y 或者 return right y。还可以把左手或者右手上拿的货物装进背包里。记为keep left 或 keep right。

        货物口的货物满足后进先出的原则。T组输入,T<=100, 每组输入第一行一个K(K<=100),代表这个人的操作的个数,下面是K行,每行一个命令,命令有如下:

take left x(数字)
take right x(数字)
return left x
return right x
keep left
keep right

每个人输出一行,输出他要付的钱。

分析:每个货物口用一个栈模拟,记录这个人当前左手和右手的货物编号,模拟即可。(其实不用一开始每个都push 10000个货物模拟OO,只要在取货的时候,判断如果栈空了,就取一个a[i]即可)

%100 AC

#include 
using namespace std;
const int N = 200;
stack<int> st[N];
int price[N]; 
char hand[100],op[100];
int main(void) {
	int n,m,k,id;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) {
		scanf("%d",price+i);
		for(int j=1;j<=10001;++j)
			st[i].push(price[i]);
	}
	for(int i=1;i<=m;++i) {
		scanf("%d",&k);
		int man[2] = {0};
		int hands = -1;
		man[0] = man[1] = 0;
		int tot = 0;
		while(k--) {
			scanf("%s%s",hand,op);
			if(strcmp("keep",op)!=0) scanf("%d",&id);
			if(strcmp(hand,"left")==0) hands = 0;
			else hands = 1;
			if(strcmp(op,"take")==0) {
				man[hands] = st[id].top();
				st[id].pop();
			}
			else if(strcmp(op,"return")==0) {
				st[id].push(man[hands]);
				man[hands] = -1;
			}
			else {
				tot += man[hands];
				man[hands] = -1;
			}
		}
		if(man[0]!=-1) tot+=man[0];
		if(man[1]!=-1) tot+=man[1];
		printf("%d\n",tot);
	}
	return 0;
} 

第2题,计算电子显示器的刷新次数

题意:

        一个h*w的显示器,要在上面显示一个图像平移的动画。图像大小为q*p。(1<=p,q,h,w<=100)。 在显示器上面显示背景,然后图像要覆盖背景。图像开始的时候左上角的位置在(stx,sty)(可能是负数)每次图像向右移动dy,向左移动dx,屏幕的每个单元格,如果和上次的字符不一样,就需要刷新。问最少刷新几次?
T组输入,保证dx和dy不同时为0。

Sample Input(凭记忆)

1
4 4
....
....
....
....
3 3
.o.
/|\
./\
0 0 1 1

Sample Output

26

分析:每次的图像如下:

开始屏幕只有背景
....
....
....
....

第一次的图像:
|\..
/\..
....
....

第二次的图像:
.o..
/|\.
./\.
....

第三次的图像
....
..o.
./|\
../\

第四次的图像
....
....
...o
../|

第五次就出去了
....
....
....
....

思路就是按题意模拟,不到为什么TLE, 只过了20%的数据,具体做法见代码

#include 
using namespace std;
const int N = 200;
char a[N][N]; //存背景 
char b[N][N]; //存动画 
char pre[N][N]; //存上一次屏幕的内容
char c[N][N]; //存当前品屏幕内容
int main(void) {
	int T,w,h,p,q,dx,dy,stx,sty;
	scanf("%d",&T); //T组输入 
	while(T--) {
		scanf("%d%d",&w,&h);
		for(int i=1;i<=h;++i) { //输入背景 
			scanf("%s",a[i]+1);
		} 
		scanf("%d%d",&p,&q);
		for(int i=1;i<=q;++i) { //输入图像 
			scanf("%s",b[i]+1);
		}
		scanf("%d%d%d%d",&stx,&sty,&dy,&dx);
		int x1 = stx, x2 = stx+q-1, y1 = sty, y2 = sty+p-1;
		bool existx = true,existy = true;
		if((x1>h&&dx>=0)||(x2<1&&dx<=0)) existx = false;
		if((y1>w&&dy>=0)||(y2<1&&dy<=0)) existy = false;
		if(!existx&&!existy) { //如果图像根本不会在屏幕上出现,直接输出0 
			puts("0");continue; 
		} 
		int flag = 0;
		int ans = 0;
		for(int i=1;i<=h;++i)
			for(int j=1;j<=w;++j)
				pre[i][j] = a[i][j];
		int nowx1 = stx, nowy1=sty; //记录图像左上角的结点 
		while(1) { //模拟 
			bool in = false;
			int xx1 = nowx1,xx2 = nowx1+q-1;
			int yy1 = nowy1,yy2 = nowy1+p-1;
			if((xx1>h||xx2<1)||(yy1>w||yy2<1)) in = false;
			else in = true;
			if(in) flag = true; 
			else{ //如果这次没在拼命上出现,之前出现过了,说明已经远离屏幕了 
				if(flag) break;
				else {
					nowx1 += dx;
					nowy1 += dy;
					continue; 
				}
			}
			for(int i=1;i<=h;++i) {  //先画背景 
				for(int j=1;j<=w;++j)
					c[i][j] = a[i][j];
			}
			for(int i=0;i<q;++i) { //再在背景上画图 
				for(int j=0;j<p;++j) {
					if(i+nowx1>=1&&i+nowx1<=h&&j+nowy1>=1&&j+nowy1<=w) {
						c[i+nowx1][j+nowy1] = b[i+1][j+1];
					}
				}
			}
			int cnt = 0;
			for(int i=1;i<=h;++i) {
				for(int j=1;j<=w;++j) { //对比这次和上一次的不同。计数 
					if(c[i][j]!=pre[i][j]) ++cnt;
					pre[i][j] = c[i][j];
				}
			}
			ans += cnt; //累计答案 
			nowx1+=dx;  
			nowy1+=dy;
		}
		printf("%d\n",ans);
	} 
	return 0;
} 

第三题:走迷宫

题意:

        有一个迷宫,你不知道整体情况,只可以试探。用0,1,2,3分别代表上,下,左,右。每次试探,如果可以走,返回1,并且走到试探的位置,如果不可以走,说明有障碍物或者是边界,呆在原地。一共试探了n次,n<=1000,000。保证最后一次试探走到了终点,返回为1。问你从约起点到终点的最短路径长度是多少?
T组输入,T<=100, 每组输入第一行为n,代表试探的次数,n<=1E6。每组输出起点到终点的最少步数。

Sample Input

3
10
0 1
0 -1 
1 1
1 1
1 -1
0 1
2 1
2 -1
3 1
3 1

2
3 1
3 1
8
0 1
0 1
3 1
3 1
1 1
1 1
2 1
0 1

Sample Output

1
2
2

分析:

网易游戏开发岗笔试经历 2020.9.5 Apare_xzc_第1张图片

        题目隐含的意思是,没出现的位置都不能走,有障碍的位置也不能走,只能走到已经试探成功的,并且和当前位置相邻的位置。
        一开始以为只有走过的路才能走,就单纯地把二维坐标 映射成一位的id, 建立邻接表BFS, 没有考虑到位置的相邻关系,结果样例3就输出了8。
      然后把所有能走的点都标记,然后从起点开始,上下左右bfs。不知道为什么,说段错误,0%,很奇怪,有大佬可以看看代码吗?

#include 
using namespace std;
const int N = 1e6+100;
int dx[] = {-1,1,0,0};
int dy[]  ={0,0,-1,1}; 
map<pair<int,int>,int>mp; //每个坐标的编号 
vector<pair<int,int> > v; //编号->坐标 ,存坐标 
map<pair<int,int>,int> no; //存哪些点不能走(其实没出现过的就不能走) 
int cnt = 0; 
struct P{
	pair<int,int> pos;
	int step;
	P(){}
	P(pair<int,int>p,int st) {
		pos = p;step = st;
	}
};
map<pair<int,int>,int> vis;
int bfs() {
	if(cnt-1==0) return 0;
	vis.clear();
	queue<P> Q; //first:id, second step
	pair<int,int> st(0,0);
	pair<int,int> ed = v[cnt-1];
	
	Q.push(P(st,0));
	vis[st] = 1;
	while(!Q.empty()) {
		pair<int,int> now = Q.front().pos;
		int step = Q.front().step;
		Q.pop();
		int x = now.first, y = now.second;
		for(int i=0;i<4;++i) {
			int xx = x+dx[i];
			int yy = y+dy[i];
			pair<int,int> to(xx,yy);
			if(no.find(to)!=no.end()||mp.find(to)==mp.end()) continue;
			if(to==ed) return step+1;
			if(vis.find(to)!=vis.end()) continue;
			vis[to] = 1;
			Q.push(P(to,step+1)); 
		}
		
	}
	return -1;
}
int main(void) {
	freopen("inC.txt","r",stdin);
	int T,n;
	scanf("%d",&T);
	while(T--) {
		v.clear();
		mp.clear();
		no.clear();
		scanf("%d",&n);
		cnt = 0;
		int x = 0,y = 0;
		pair<int,int> pr(0,0);
		v.push_back(pr);
		mp[pr] = cnt++;
		int op,res;
		while(n--) {
			scanf("%d%d",&op,&res);
			if(res==-1) {
				no[make_pair(x+dx[op],y+dy[op])] = 1;	
				continue;
			}
			int xx = x+dx[op];
			int yy = y+dy[op];
			pr.first = xx; pr.second = yy;
			auto it = mp.find(pr);
			if(it==mp.end()) {
				v.push_back(pr);
				mp[pr] = cnt++;
			}
			x = xx; y = yy;
		}
		printf("%d\n",bfs());
	}	
	return 0;
} 

4. 序列

给一个序列,你需要排序,排序之后,要满足a[i] * a[i+1] <= a[i+1] * a[i+2]
如 1,2,3,4
输出1,2,3,4

分析:

        就剩下10分钟了,想到了正确思路,但是细节没处理好,j++写成了i++。思路是这样的,正数从大到小排,负数从小到大排,然后正负数交替。如果负数没了,就从小到大输出剩下的正数,如果正数没了,就从大到小输出负数。

但是注意,正数或者负数没了,就立刻break。

#include 
using namespace std;
int a[1000000];
vector<int> v1,v2;
int main(void) {
	int n;
	cin>>n;
	int x;
	for(int i=1;i<=n;++i) {
		scanf("%d",&x);
		if(x>=0) v2.push_back(x);
		else v1.push_back(x); 
	}
	sort(v1.begin(),v1.end());
	sort(v2.begin(),v2.end(),[](int a,int b){return a>b;
	});
	int len1 = v1.size(),len2 = v2.size();
	int i = 0, j = 0;
//	while(i
//		printf("%d %d ",v1[i++],v2[j++]);
//	}
	while(i<len1&&j<len2) {
		printf("%d ",v1[i++]);
		if(i==len1) break;
		printf("%d ",v2[j++]);
		if(j==len2) break;
	} 
	if(i<len1) {
		sort(v1.begin()+i,v1.end(),[](int a,int b){return a>b;
	});
		for(int ii=i;ii<len1;++ii) cout<<v1[ii]<<" ";
		cout<<endl;return 0; 
	}
	else {
		sort(v2.begin()+j,v2.end());
		for(int jj=j;jj<len2;++jj) cout<<v2[jj]<<" ";cout<<endl;
	}	
	return 0;
} 

应该改了之后就没问题了

牛客上一个300分的帖子


你可能感兴趣的:(笔试,网易,解题报告,网易互娱游戏开发笔试2021,自动贩卖机,排列)