codility上的问题 之七 Zeta 2011

来源:互联网 发布:梦里花落知多少txt下载 编辑:程序博客网 时间:2024/06/06 02:58

  这个题比较有意思,有N行M列的正方形盒子。每个盒子有三种状态0, -1, +1。我们要扔球,球可以从盒子上面的边或者左面的边进入盒子,从下面的边或者右面的边离开盒子。规则:

如果盒子的模式是-1,则进入它的球从下面出去。(方向变为向下)

如果盒子的模式是+1,则进入它的球从右面出去。 (反向变为向右)

如果盒子的模式是0, 则进入它的球方向不变。从上面进入的,从下面出去,从左面进入的,从右面出去。


球离开一个盒子,这个盒子的模式变为相反数。


已知,每个盒子的状态,扔k个球,它们都从左上角那个盒子的上面进入(方向向下),问最终有几个球从右下角的盒子的下边出去。(可以理解维球一个一个放,等待的时间足够长,不会有两个球同时进入一个盒子的情形)。


数据范围 

N [1..1000]

M [1..1000]

K [0..10^9]

复杂度要求:

时间O(N*M)

空间O(M)

分析:

   这个题比较有意思。K那么大,直接模拟肯定不行。我们先考虑一个盒子的情况,如果它的状态是-1,一共b个球进入它的花,会有b/2个求从右面出去 b - b / 2个球从下面出去,同理要是+1的话b个球有b/2个球从下面出去,b - b/2个球从右面出去。 我们假设dp[i][j]表示有多少个球今日第j个球,我们从左到右,从上到下来算dp[i][j]。

进入(i,j)的有两方面球,一方面是(i,j - 1)从右边出来的,这个实际上按照(i,j - 1)的模式能算出来,另外一方面是(i - 1, j)从下面出来的,这个实际上也能从dp[i - 1][j]计算出来,我们考虑的顺序是从上到下,从左到右,所以考虑的盒子不用再考虑第二次,因为所有的球已经通过了。另外就是可以省掉一维数组表示状态,才能达到空间复杂度的要求。

代码:

// you can also use includes, for example:// #include <algorithm>int solution(const vector< vector<int> > &A, int K) {    // write your code here...    int i,j,right,n = A.size(), m = A[0].size();    vector<int> dp;    dp.resize(m, 0);    dp[0] = K;    for (i = 0; i < n; ++i) {        for (j = right = 0; j < m; ++j) {            K = dp[j] + right;            if (A[i][j] > 0) {                dp[j] = K >> 1;            }            else if (A[i][j] < 0) {                dp[j] = (K + 1) >> 1;            }            right = K - dp[j];        }    }    return dp[m - 1];                                }




原创粉丝点击