1

私は面接の質問を調べているときに出くわしたこの質問をしようとしていました。各行と列に少なくとも1つのコインが含まれるように、rコインを*mグリッドに配置する方法の数を尋ねられます。

グリッド内の各セルを主要な順序で処理するバックトラッキングソリューションを考え、このように再帰を設定しました。毎回0を出力するので、私のアプローチは間違っているようです。誰かが私のアプローチのエラーを見つけるのを手伝ってくれませんか。?ありがとう。

制約。n、m<200およびr<n * m;

これが私が思いついたコードです。

#include<cstdio>
#define N 201
int n, m , r;
int used[N][N];
int grid[N][N] ;  // 1 is coin is placed . 0 otherwise. // -1 undecided.

bool isOk()
{
    int rows[N];
    int cols[N];

    for(int i = 0 ; i < n ; i++) rows[i] = 0;
    for(int i = 0 ; i < m ; i++) cols[i] = 0;
    int sum = 0;
    for(int i = 0 ; i < n ; i++)for(int j = 0; j < m ; j++)
    {
        if(grid[i][j]==1)
        {
            rows[i]++;
            cols[j]++;
            sum++;  
        }
    }
    for(int i = 0 ; i < n ; i++) 
    {
        if(rows[i]==0) return false;
    }

    for(int j = 0 ; j < n ; j++)
    {
        if(cols[j]==0) return false;
    }
    if(sum==r) return true;
    else return false;
}

int calc_ways(int row , int col,  int coins)
{
    if(row >= n) return 0;
    if(col >= m) return 0;
    if(coins > r) return 0;
    if(coins == r) 
    {
        bool res = isOk();
        if(res) return 1; 
        else 0;
    }

    if(row == n - 1 and col== m- 1) 
    {
        bool res = isOk();
        if(res) return 1;
        else return 0;
    }

    int nrow, ncol;

    if(col + 1 >= m)
    {
        nrow = row + 1;
        ncol = 0;
    }
    else
    {
        nrow = row;
        ncol = col + 1;
    }
    if(used[row][col]) return calc_ways(nrow, ncol, coins);
    int ans =  0;
    used[row][col] = 1;
    grid[row][col] = 0;
    ans += calc_ways(nrow , ncol , coins);

    grid[row][col] = 1;
    ans += calc_ways(nrow , ncol , coins + 1);

    return ans;
}

int main()
{
    int t;
    scanf("%d" , &t);
    while(t--)
    {
        scanf("%d %d %d" , &n , &m , &r);
        for(int i = 0 ; i <= n ; i++)
        {
            for(int j = 0; j <= m ; j++)
            {
                used[i][j] = 0;
                grid[i][j] = -1;
            }
        }
        printf("%d\n" , calc_ways(0  ,  0 , 0 ));
    }
    return 0;
}
4

3 に答える 3

3

これを解決するためのプログラムはほとんど必要ありません。

一般性を失うことなく、m<=nとします。

まず、n <= rでなければなりません。そうでない場合、解決策はありません。

次に、問題をサイズmxmの正方形に分割し、その上に主対角線に沿ってm個のコインを配置し、残りの部分にn-m個のコインを配置して残りの条件を満たすようにします。

正方形の主対角線に沿ってコインを配置する方法が1つあります。

残りの部分にはm^(n --m)の可能性があります。これまでの合計をnで並べ替えることができます!ただし、それらのいくつかは重複します(学生の演習として残っている数)。

さらに、r-n枚のコインが残っており、(m-1)n枚のコインが残っています。

これらをすべてまとめると、次の上限があります。

1 x m^(n - m) x n! x C((m - 1)n, r - n)

問題の解決策。この数を重複する順列の数で割ると完了です。

于 2012-07-24T23:07:30.577 に答える
0

問題1

コードは、各正方形にコインを置き、各正方形に使用済みのマークを付けることから始まります。

次に、最終位置をテストし、最終位置がrコインの目標を満たしていないことを決定します。

次に、バックトラックを開始しますが、used [row] [col]が1に設定されており、これによりコインを配置するためのコードが短絡されるため、実際には別の選択を試みることはありません。

つまり、1つの問題は、「使用済み」のエントリが設定されているが、再帰中にクリアされないことです。

問題2

コードのもう1つの問題は、n、mのサイズが200の場合、完了しないことです。

問題は、このバックトラッキングコードが複雑さO(2 ^(n * m))であるということです。これは、コインを配置するすべての可能な組み合わせを試行するためです(n = m = 200 ...の多くの宇宙寿命...)。

別のアプローチを検討することをお勧めします。たとえば、動的計画法を検討して、ボードの残りの「a」列に「k」コインを配置する方法がいくつあるかを計算して、コインをボードの「b」行に配置するようにすることができます。現在コインがないボード。

于 2012-07-23T18:38:15.527 に答える
0

これは、dグリッドがrコインで埋められる合計の方法として扱うことができます-(単一の行を残してdの残りを埋める合計の方法-単一の列を残してdの残りを埋める合計の方法-行と列を残す合計の方法一緒にndfillingdrest)これは

p(n*m ,r) -( (p((n-1)*m , r) * c(n,1)) +(p((m-1)*n , r) * c(m,1))+(p((n-1)*(m-1) , r) * c(n,1)*c(m,1)) )

私はそう思いますが、よくわかりません!

于 2012-12-26T09:01:24.120 に答える