网易游戏2011.10.15校园招聘笔试题

1、对于一个内存地址是32位、内存页是8KB的系统。0X0005F123这个地址的页号与页内偏移分别是多少。

页面大小是8KB,那么页内偏移量是从0x0000(0)~ 0x1FFF(2的13次方 - 1)。0x5F123/8K=2E,余数是1123;则页号是47页,页内偏移量应该是0X00001123

2、如果X大于0并小于65536,用移位法计算X乘以255的值为:    (X<<8)-X

X<<8-X是不对的,因为移位运算符的优先级没有减号的优先级高,首先计算8-X为0,X左移0位还是8。

3、一个包含n个节点的四叉树,每个节点都有四个指向孩子节点的指针,这4n个指针中有  3n+1   个空指针。

4、以下两个语句的区别是:第一个动态申请的空间里面的值是随机值,第二个进行了初始化,里面的值为0

int *p1 = new int[10];
int *p2 = new int[10]();

5、计算机在内存中存储数据时使用了大、小端模式,请分别写出A=0X123456在不同情况下的首字节是,大端模式:0X12      小端模式:0X56           X86结构的计算机使用  小端    模式。

一般来说,大部分用户的操作系统(如windows, FreeBsd,Linux)是小端模式的。少部分,如MAC OS,是大端模式 的。

6、在游戏设计中,经常会根据不同的游戏状态调用不同的函数,我们可以通过函数指针来实现这一功能,请声明一个参数为int *,返回值为int的函数指针:

int (*fun)(int *)

7、下面程序运行后的结果为:to test something

char str[] = "glad to test something";
char *p = str;
p++;  //字符占一个字节p++后p指向l
int *p1 = static_cast<int *>(p);
p1++;  //整型占四个字节p1++后指向t
p = static_cast<char *>(p1);
printf("result is %s\n",p);

8、在一冒险游戏里,你见到一个宝箱,身上有N把钥匙,其中一把可以打开宝箱,假如没有任何提示,随机尝试,问:

(1)恰好第K次(1=<K<=N)打开宝箱的概率是多少。  (1-1/n)*(1-1/(n-1))*(1-1/(n-2))***(1/(n-k+1)) = 1/n

(2)平均需要尝试多少次。

 这个就是求期望值   由于每次打开宝箱的概率都是1/n,则期望值为:   1*(1/n)+2*(1/n)+3*(1/n)+......+n*(1/n) = (n+1)/2

9、头文件中ifndef / define / endif 是做什么用的?防止该头文件被重复引用。
10、代码里有时可以看到extern “C”,这语句是做什么用的?

首先,作为extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样,模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但是并不会报错;它会在连接阶段中从模块A编译生成的目标代码中找到此函数
extern "C"是连接申明(linkage declaration),被extern "C"修饰的变量和函数是按照C语言方式编译和连接的,来看看C++中对类似C的函数是怎样编译的:

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
  
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。

_foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。
同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。


11、平均要取多少个(0,1)中的随机数才能让和超过1。

 

12、在下列乘法算式中,每个字母代表0~9的一个数字,而且不同的字母代表不同的数字:

 ABCDEFGH

*                 AJ

------------------

EJAHFDGKC

BDFHAJEC

------------------

CCCCCCCCC

请写出推导的过程。

本题唯一解为:A=2、B=4、C=6、D=9、E=1、F=3、G=5、H=8、J=7、K=0

13、输入格式:第一行输入N(N<=100)表示流通的纸币面额数量;第二行N个纸币的具体表示的面额,从小到大排列,取值【1,10^6】。
输出格式:输出一个整数,表示应该发行的纸币面额,这个整数是已经发行的所有纸币面额都无法表示的最小整数。(已经发行的每个纸币面额最多只能使用一次)

 

输入

输出

5

1 2 3 9 100

7

5

1 2 4 9 100

8

5

1 2 4 7 100

15

 

思路:这是一个典型的母函数问题,一般的典型母函数如 G(x)=  (1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*(1+x^3+x^6+x^9+x^12....).....

这个题目中的每个纸币只能够使用0次或1次,在上面的那个一般的母函数的基础上修改一下就行了,就很简单了。。

具体代码如下:

#include <iostream>
using namespace std;

const int lmax=10000;
int c1[lmax+1],c2[lmax+1];

int main(void)
{
    int m,n,i,j,k,a[110];
    //计算的方法还是模拟手动运算,一个括号一个括号的计算,从前往后
    while (cin>>m && m)
    {
        n=0;
        for(i = 0; i < m; i++)
        {
            scanf("%d",&a[i]);
            n += a[i];
        }
        n += 5;     //有可能无法表示的那个数比所有纸币面额的总和还要大
        for(i = 0; i <= n; i++)
        {
            c1[i] = 0;
            c2[i] = 0;
        }
        for(i = 0; i < 2*a[0]; i += a[0])        //母函数的表达式中第一个括号内的各项系数
            c1[i] = 1;
        //第一层循环是一共有 n 个小括号,而刚才已经算过一个了,所以是从2 到 n 
        // i 就是代表的母函数中第几个大括号中的表达式
        for(i = 2; i <= m; i++)
        {
            for(j = 0; j <= n; j++)              //j 就是指的已经计算出的各项的系数
            {
                for (k = 0; k < 2*a[i-1]; k += a[i-1])      //k 就是指将要计算的那个括号中的项
                { 
                    c2[j+k] += c1[j];        //合并同类项,他们的系数要加在一起,所以是加法
                }
            }
            for(j = 0; j <= n; j++)    // 刷新一下数据,继续下一次计算,就是下一个括号里面的每一项
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        for(i = 1; i <= n; i++)
        {
            if(c1[i] == 0)
            {
                cout<<i<<endl;      //找出第一个无法表示的纸币面额
                break;
            }
        }
    }
    return 0;
}
分析过程:
设N表示面额数量,v[i]表示第i个纸币的面额,其中i=1,...,N。
设s[i]=v[1]+...+v[i],则s[i]表示前i个纸币面额的总和。
要解决下面这个问题:
如果所有小于等于s[i]的正整数都能表示,那么所有小于等于s[i+1]的正整数在什么情况下也能全部表示?
充要条件是s[i]+1>=v[i+1]。
必要性:
首先如果s[i]+1<v[i+1],则s[i]+1不能表示。因为前i项之和为s[i],小于s[i]+1,所以不可能通过前i项的组合得到s[i]+1。必须加入v[i+1],v[i+2],...,v[N]中的一项或几项。但v[N]>...>v[i+2]>v[i+1]>s[i]+1,所以也不可能得到s[i]+1。所以s[i]+1>=v[i+1]是所有小于等于s[i+1]的正整数能够表示的必要条件。
充分性:
已知所有小于等于s[i]的正整数都能表示。那么只需要考虑大于s[i],小于等于s[i+1]的正整数。设其为p,s[i]<p<=s[i+1]。如果对于任意的p,p=v[i+1]+(p-v[i+1])。p-v[i+1]>=p-(s[i]+1)=(p-s[i])+1>1>0为正整数,并且p-v[i+1]<=s[i+1]-v[i+1]=s[i],所以p-v[i+1],能够通过前i项的组合得到,假定这个组合为C。所以p可以通过C与第i+1项的组合得到。所以所有小于s[i+1]的项都能通过整数表示。s[i]+1>=v[i+1]所有小于等于s[i+1]的正整数能够表示的充分条件。
综上s[i]+1>=v[i+1]是充要条件。
由于要判断s[1]=v[1]的情况。比如v[1]=10,那么最小面额的纸币为10。不能表示的最小整数为1。所以我们也引入s[0]和v[0]。令s[0]=v[0]=0。它们的含义是,v[0]表示面额为0的纸币,s[0]表示需要表示的总和为0整数。
s[i]=v[0]+v[1]+...+v[i]=v[1]+...+v[i]的值依然保持不变。
s[0]=v[0]。只要通过取一张面额为0的纸币即可得到s[0]。
这样做就可以判断v[1]是否满足要求。把i=0代入式子得,s[0]+1>=v[1],即v[1]<=1,而v[1]>0,所以v[1]=1。当然也可以另外判断v[1]是否满足条件v[1]=1。
综上,我们要寻找的最小的那个不能表示的正整数是s[i]+1,并且满足如下式子s[i]+1<v[i+1]。
 
下面的程序完成了上面的分析。只是索引从0开始,而不是1。

 

int _tmain(int argc, _TCHAR* argv[])
{
    const int MAX = 100;
    int a[MAX];
    int m = 0;

    while (cin >> m && m)
    {
        for(int i = 0; i < m; i++)
        {
            std::cin >> a[i];
        }

        for (int i = 0, s = 0; i < m; i++)
        {
            if (s + 1 < a[i])
            {
                std::cout << s + 1 << std::endl;
                break;
            }
            s += a[i];
        }
    }

    return 0;
}

 

posted @ 2013-08-24 22:33  一枚程序员  阅读(4363)  评论(1编辑  收藏  举报