1. 程式人生 > >[USACO06NOV]玉米田Corn Fields

[USACO06NOV]玉米田Corn Fields

題目

思路

資料大小已經很明顯的提示,這題是狀壓DP啊!

讀入以後,我們用F[i]來表示第i行上的草地情況,這裡F數組裡的是二進位制數。MAXSTATE是2n,也就是這道題的最大狀態(n列都是1)。

然後我們在0~MAXSTATE-1這些狀態裡找到合法狀態,也就是不能兩頭牛的草地是相鄰的。判斷方法就是把這個二進位制數左移一位and,然後右移一位and。如果這個狀態是合法的,那麼都應該返回0。

然後就開始動規,從第一行開始,在每行裡找所有狀態,如果這個狀態是合法的,且不會在貧瘠的草地上(和(j & F[i]) == j說明沒有草地種在貧瘠的地方),那麼接下來開始找上一行的合法情況(上下兩行之間沒有相鄰的草地),把上一行的情況數加到f[i][j]裡。

最後把最下面一行的每一列的情況書統統加起來,就是答案啦~

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,w;
int a[20],f[1<<18],g[1<<18];
int main()
{
    scanf("%d%d",&n,&w);
    for(int i=1; i<=n; i++) scanf("%d",&a[i]);
    memset(f,63,sizeof(f));
    f[0]=1;
    g[0]=w;
    for(int i=0; i<(1<<n); i++) 
    {
        for(int j=1; j<=n; j++)
        {
            if(i&(1<<(j-1))) continue;
            if(g[i]>=a[j] && f[i|(1<<(j-1))]>=f[i])
            {
                f[i|(1<<(j-1))]=f[i];
                g[i|(1<<(j-1))]=max(g[i|(1<<(j-1))],g[i]-a[j]);
            }
            else if(g[i]<a[j] && f[i|(1<<(j-1))]>=f[i]+1)
            {
                f[i|(1<<(j-1))]=f[i]+1;
                g[i|(1<<(j-1))]=max(g[i|(1<<(j-1))],w-a[j]);
            }
        }
    }
    printf("%d",f[(1<<n)-1]);
    return 0;
}