網易游戲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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM