power oj 1557种树[二进制状压DP]

题目链接【https://www.oj.swust.edu.cn/problem/show/1557】

题意:中文题目。

题解:用0,1表示某个位置是否种了树,先算出同一行的有效状态的总数,即开两个1状态不能相邻的状态。

枚举每一行的状态然后根据行一行的状态判断改状态是否有效,然后对最后一行的所有有效状态求最大值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int bas[105], k[150], N[150];
int dp[105][150];
char s[105];
int n, m, nu;
void init()
{
    memset(dp, 0, sizeof(dp));
    memset(bas, 0, sizeof(bas));
    memset(N, 0, sizeof(N));
    nu = 0;
}
int main ()
{
    while(~scanf("%d%d", &n, &m))
    {
        if(n == 0 && m == 0)
            break;
        init();
        for(int i = 1; i <= n; i++)
        {
            scanf("%s", s);
            for(int j = 0; j < m; j++)
            {
                if(s[j] == '*')
                    bas[i] += (1 << j);
            }
        }
        for(int i = 0; i <= (1 << m) - 1; i++)
        {
            if((!(i & (i << 1))) && (!(i & (i >> 1))))//有效状态
            {
                k[nu] = i;
                int t = i;
                while(t)
                {
                    if(t & 1) N[nu]++;
                    t >>= 1;
                }
                nu++;
            }
        }
        for(int j = 0; j < nu; j++)
        {
            if(!(k[j]&bas[1]))
                dp[1][j] = N[j];
        }
        for(int i = 2; i <= n; i++)
        {
            for(int j = 0 ; j < nu; j++)//i行
            {
                if(k[j]&bas[i]) continue;//判断第i行
                for(int t = 0; t < nu; t++)
                {
                    if(k[t]&bas[i - 1]) continue; //判断第i-1行
                    if((k[t]&k[j]) || (k[t] & (k[j] << 1)) || (k[t] & (k[j] >> 1))) continue;
                    dp[i][j] = max(dp[i][j], dp[i - 1][t] + N[j]);
                }
            }
        }
        int ans = 0;
        for(int i = 0; i < nu; i++)
            ans = max(dp[n][i], ans);
        printf("%d
", ans);
    }
    return 0;
}
想的太多,做的太少。
原文地址:https://www.cnblogs.com/pealicx/p/6234699.html