1

この問題を解決しようとしていますが、解決策が見つかりません:

N 行 M 列に配置された正方形からなるボードが与えられます。このボードのタイリングは、それを覆うタイルのパターンです。次の場合、タイリングは興味深いものです。

    only tiles of size 1x1 and/or 2x2 are used;
    each tile of size 1x1 covers exactly one whole square;
    each tile of size 2x2 covers exactly four whole squares;
    each square of the board is covered by exactly one tile.

たとえば、次の画像は、サイズが 4 行 3 列のボードのいくつかの興味深いタイリングを示しています

ボードの 2 つの興味深いタイリングは、一方のタイリングではサイズ 1x1 のタイルで覆われ、他方ではサイズ 2x2 のタイルで覆われている正方形がボード上に少なくとも 1 つ存在する場合、異なります。たとえば、上の画像に示されているすべてのタイリングは異なります。

関数を書く

int count_tilings(int N, int M); 

これは、2 つの整数 N と M を指定すると、サイズが N 行 M 列のボードの異なる興味深いタイルの数のモジュロ 10,000,007 の剰余を返します。

と仮定する:

    N is an integer within the range [1..1,000,000];
    M is an integer within the range [1..7].

たとえば、N = 4 および M = 3 の場合、この関数は 11 を返す必要があります。これは、サイズが 4 行 3 列のボードに 11 の異なる興味深いタイリングがあるためです。

http://dabi.altervista.org/images/task.img.4x3_tilings_all.gif

(4,3) の結果は 11、(6,5) の結果は 1213 です。次のことを試しましたが、うまくいきません。

static public int count_tilings ( int N,int M ) {

    int result=1;
    if ((N==1)||(M==1)) return 1;

    result=result+(N-1)*(M-1);

    int max_tiling=  (int) ((int)(Math.ceil(N/2))*(Math.ceil(M/2)));
    System.out.println(max_tiling);
    for (int i=2; i<=(max_tiling);i++){
        if (N>=2*i){
            int n=i+(N-i);
            int k=i;
            //System.out.println("M-1->"+(M-1) +"i->"+i);
            System.out.println("(M-1)^i)->"+(Math.pow((M-1),i)));
            System.out.println( "n="+n+ " k="+k);
            System.out.println(combinations(n, k));
            if (N-i*2>0){
                result+= Math.pow((M-1),i)*combinations(n, k);
            }else{
                result+= Math.pow((M-1),i);
            }
        }
        if (M>=2*i){
            int n=i+(M-i);
            int k=i;
            System.out.println("(N-1)^i)->"+(Math.pow((N-1),i)));
            System.out.println( "n="+n+ " k="+k);
            System.out.println(combinations(n, k));
            if (M-i*2>0){
                result+= Math.pow((N-1),i)*combinations(n, k);
            }else{
                result+= Math.pow((N-1),i);
            }
        }

    }
    return result;
}
static long combinations(int n, int k) {
    /*binomial coefficient*/
    long coeff = 1;
    for (int i = n - k + 1; i <= n; i++) {
        coeff *= i;
    }
    for (int i = 1; i <= k; i++) {
        coeff /= i;
    }
    return coeff;
}
4

2 に答える 2

2

これは宿題なので、完全な解決策は示しませんが、いくつかのヒントを示します。

まず、再帰的な解決策を次に示します。

class Program
{
    // Important note:
    // The value of masks given here is hard-coded for m == 5.
    // In a complete solution, you need to calculate the masks for the
    // actual value of m given. See explanation in answer for more details.

    int[] masks = { 0, 3, 6, 12, 15, 24, 27, 30 };

    int CountTilings(int n, int m, int s = 0)
    {
        if (n == 1) { return 1; }

        int result = 0;
        foreach (int mask in masks)
        {
            if ((mask & s) == 0)
            {
                result += CountTilings(n - 1, m, mask);
            }
        }
        return result;
    }

    public static void Main()
    {
        Program p = new Program();
        int result = p.CountTilings(6, 5);
        Console.WriteLine(result);
    }
}

オンラインでの動作を確認してください: ideone

追加のパラメーターを追加したことに注意してくださいs。これは、最初の列の内容を格納します。最初の列が空の場合、s = 0 です。最初の列に塗りつぶされた正方形が含まれている場合、s の対応するビットが設定されます。最初は s = 0 ですが、2 x 2 のタイルが配置されると、次の列のいくつかの正方形が埋められます。これは、再帰呼び出しで s がゼロ以外になることを意味します。

変数はハードコードされていmasksますが、完全なソリューションでは、 の実際の値に基づいて計算する必要がありますm。に格納されmasksている値は、バイナリ表現を見るとより意味があります。

00000
00011
00110
01100
01111
11000
11011
11110

つまり、m ビットの 2 進数でビットのペアを設定するすべての方法です。これらすべての可能性を生成するコードを書くことができます。または、 m の可能な値は 7 つしかないため、 の 7 つの可能性すべてをハードコーディングすることもできますmasks


ただし、再帰的な解決策には 2 つの深刻な問題があります。

  1. の値が大きいと、スタックがオーバーフローしますN
  2. 計算には指数時間が必要です。の値が小さい場合でも、信じられないほど遅いです。N

これらの問題は両方とも、アルゴリズムを反復的に書き直すことで解決できます。to beのすべての可能な値についてm、定数を保持し、結果を初期化します。これは、列が 1 つしかない場合は 1x1 タイルのみを使用する必要があり、これを行う方法は 1 つしかないためです。n = 1s1

の結果を使用して、n = 2のすべての可能な値を計算できます。に到達するまで、これを繰り返すことができます。このアルゴリズムは、 に関して線形時間で完了し、一定の空間を必要とします。sn = 1n = NN

于 2012-08-25T17:40:48.413 に答える
0

再帰的な解決策は次のとおりです。

// time used : 27 min
#include <set>
#include <vector>
#include <iostream>
using namespace std;
void placement(int n, set< vector <int> > & p){
    for (int i = 0; i < n -1 ; i ++){
        for (set<vector<int> > :: iterator j  = p.begin(); j != p.end(); j ++){
            vector <int> temp = *j;
            if (temp[i] == 1 || temp[i+1] == 1) continue;
            temp[i] = 1; temp[i+1] = 1;
            p.insert(temp);
        }
    }
}

vector<vector<int> > placement( int n){
    if (n > 7) throw "error";
    set <vector <int> > p;
    vector <int> temp (n,0);
    p.insert (temp);
    for (int i = 0; i < 3; i ++) placement(n, p);
    vector <vector <int> > s;
    s.assign (p.begin(), p.end());
    return s;
}


bool tryput(vector <vector <int> > &board, int current, vector<int> & comb){
    for (int i = 0; i < comb.size(); i ++){
        if ((board[current][i] == 1 || board[current+1][i]) && comb[i] == 1) return false;
    }
    return true;
}
void  put(vector <vector <int> > &board, int current, vector<int> & comb){
    for (int i = 0; i < comb.size(); i ++){
        if (comb[i] == 1){
            board[current][i] = 1;
            board[current+1][i] = 1;
        }
    }
    return;
}

void  undo(vector <vector <int> > &board, int current, vector<int> & comb){
    for (int i = 0; i < comb.size(); i ++){
        if (comb[i] == 1){
            board[current][i] = 0;
            board[current+1][i] = 0;
        }
    }
    return;
}



int place (vector <vector <int> > &board, int current,  vector < vector <int> >  & all_comb){
    int m = board.size();
    if (current >= m) throw "error";
    if (current == m - 1) return 1;
    int count = 0;
    for (int i = 0; i < all_comb.size(); i ++){
        if (tryput(board, current, all_comb[i])){
            put(board, current, all_comb[i]);
            count += place(board, current+1, all_comb) % 10000007;
            undo(board, current, all_comb[i]);
        }
    }
    return count;
}
int place (int m, int n){
    if (m == 0) return 0;
    if (m == 1) return 1;
    vector < vector <int> > all_comb = placement(n);
    vector <vector <int> > board(m, vector<int>(n, 0));
    return place (board, 0, all_comb);

}
int main(){
    cout << place(3, 4) << endl;
    return 0;
}

時間の複雑さO(n^3 * exp(m))

スペースの使用量を減らすには、ビット ベクトルを試してください。

時間の複雑さを に減らすにはO(m*(n^3))、動的計画法を試してください。

O(log(m) * n^3)分割統治+動的プログラミング を試す時間の複雑さを軽減します。

幸運を

于 2012-08-30T07:36:41.877 に答える