1. 程式人生 > >校招季——程式設計題目(15、16) 約瑟夫問題 最大子矩陣和

校招季——程式設計題目(15、16) 約瑟夫問題 最大子矩陣和

15. 約瑟夫問題(題目042

題目:

n個人圍成一圈,從第一個開始報數,第m個將被殺掉,最後剩下一個,其餘人都將被殺掉。求最後剩下的人的序號。例如n=6m=5,被殺掉的人的序號為54623。最後剩下1號。

解答:

思路:

如果要列印整個過程,有3種方法:

1.連結串列法:產生長度為n的迴圈連結串列,然後每遍歷m次輸出當前序號,並刪除節點,直到連結串列中只有一個元素為止。

2.陣列法:建立一個輔助陣列,初始都為0,然後每遍歷m個為0的位置就輸出當前序號,並將該位置的值改為1,直到陣列大小變成1為止。

3.陣列法:建立一個輔助陣列,其中儲存編號,每刪除一個就將後面的編號前移。

3種方法的時間複雜度都是

O(n*m),如果只需要輸出最後的序號,則可以利用一些數學手段尋找規律,簡化過程。

為了簡化問題,我們假定序號從0開始。

對於n個人的情況,第1個殺掉的人肯定是(m-1)%n號,這時剩下的人記為mm+1,…,n-10,…,m-2,將它們重新記為012,…,n-2,其中的對應關係為:

X = (x’ + m) % n

其中xn個人時的序號,x’n-1個人時的序號,令f(n)n個人時最後剩餘的人的序號,則f(n)和此時的f(n-1)應該對應著同一個人,且其編號有如上式的對應關係,即:

f(n) = (f(n-1) + m) % n

其初始條件為f(1)=0。返回結果時再將f(n)+1,從而變換成序號從

1開始的情況。

int Josephus(int n, int m)
{
    int result = 0, i;
    for (i = 2; i <= n; ++i)
        result = (result + m) % i;
    return result + 1;
}

16. 最大子矩陣和(題目052

題目:

輸入一個M*N的矩陣,其中每個元素為有正有負的整數,輸出它的最大的子矩陣元素和。如果不存在矩陣和為正數的子矩陣,返回0

解答:

方法1

簡單的三重迴圈求每個子矩陣的矩陣和,返回最大值,時間複雜度O(m3n3)

方法2

定義一個大小也為m*n的新矩陣

sub_sum,其中sub_sum[i][j]表示子矩陣{0,0}~{i,j}的矩陣和。

sub_sum[i][j] = sub_sum[i-1][j] + sub_sum[i][j-1] - sub_sum[i-1][j-1] + mt[i][j];

則對任意子矩陣{a,b}~{c,d},它的矩陣和為:

sum = sub_sum[c][d] - sub_sum[c][b-1] - sub_sum[a-1][d] + sub_sum[a-1][b-1];

總的時間複雜度為O(m2n2)

方法3

利用最大子序列和的性質,求出[si, ei]範圍內每列的和,再從其中找出最大連續子序列的和,就是要求的結果。時間複雜度O(mn2)

int MaxSubMatrixSum(const Matrix *mt)
{
    int rows = mt->rows, cols = mt->cols ,size = cols * sizeof(int);
    int *col_sum = malloc(size);
    int si, ei, j, max_sum = 0;
    for (si = 0; si < rows; ++si)
    {
        memset(col_sum, 0, size);
        for (ei = si; ei < rows; ++ei)
        {
            for (j = 0; j < cols; ++j)
                col_sum[j] += mt->data[ei][j];
            int sum = MaxSum(col_sum, cols);
            if (sum > max_sum)
                max_sum = sum;
        }
    }
    return max_sum;
}