【洛谷 P1879】【[USACO06NOV]玉米田Corn Fields】

題目:

連接數組

思路:

Q:如何想到是狀壓DP優化

A:那是由於(我看了標籤\(1 ≤ M ≤ 12; 1 ≤ N ≤ 12\)\(2 ^ {12}\) 不過才。。。(Win7計算器使用中)\(4096\)嘛! 而後若是用狀壓DP也能夠優化時空spa


肯定狀態:

\(f_{i,j}\) 表示第\(i\)行的方案(對,方案,這是方案而答案是方案數)是\(j\)(是一個二進制數,用十進制來存儲,第\(k\)位是\(1/0\)(二進制)表示\(/\)不選)時的方案數。code

肯定轉移方程:

聲明:下面的\(j,k\)都是一個合法的方案get

設已經進行到\(i\)行,此時的方案是\(j\),上一行的方案是\(k\)it

有一個特殊條件(邊界):\(i = 1\)class

既然是第一行,那麼它的因此合法方案都是正確的,因此邊界是:
\[\Large {f_{1,j} = 1}\]二進制

也能夠很容易地想到本行的合法方案的方案數是上一行的全部合法方案數,也就是:註釋

\[\Large {f_{i,j} = f_{i,j}+f_{i - 1,k}}\]di

代碼:

聲明:那個優化可能並沒有卵用。。。

const int N = 15;
int n, m;
int f[N][(1 << N)];
int st[1 << N];   //一個小小的優化數組
int a[N];
int tot;

void _init()     //一個小小的優化,判斷此方案  在這一行  是否是合法的
{
    for (int i = 0; i < (1 << m); i++)
    {
        if (i & (i << 1)) continue;
        st[++tot] = i;
    }
}

int main()
{
    scanf ("%d%d", &n, &m);
    for (int j = 1; j <= n; j++)
        for (int i = m - 1; i >= 0; i--)
        {
            int x;
            scanf ("%d",&x);
            a[j] += (x << i);  //本行的方案(可能不是合法)
        }
    _init();        //開始優化
    for (int i = 1; i <= tot; i++)         //邊界條件
    {
        if (!((st[i] | a[1]) == a[1]))continue;  //是否合法
        f[1][st[i]] = 1;
    }
    for (int i = 2; i <= n; i++)
    {
        for (int j = 1; j <= tot; j++)
        {
            if (!((st[j] | a[i]) == a[i]))continue;   //判斷合法
            for (int k = 1; k <= tot; k++)
            {
                if (!((st[k] | a[i - 1]) == a[i - 1]))continue;  //同上條註釋
                if (st[j] & st[k]) continue;
                f[i][st[j]] += f[i - 1][st[k]];      //轉移
                f[i][st[j]] %= 100000000;
            }
        }
    }
    int ans = 0;
    for (int j = 1; j <= tot; j++)             //答案
        ans += f[n][st[j]], ans %= 100000000;
    printf ("%d", ans);
    return 0;
}
相關文章
相關標籤/搜索