POJ 3254 Corn Fields(位运算,状压DP)

Corn Fields

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 19184   Accepted: 10073

Description

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can't be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input

Line 1: Two space-separated integers: M and N 
Lines 2..M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)

Output

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 3
1 1 1
0 1 0

Sample Output

9

Hint

Number the squares as follows:

1 2 3
  4  


There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.

Source

USACO 2006 November Gold

===================================

题意:

给定一个矩阵,1表示土地可用,0表示不可用,问有几种选择土地的方案,选择规则:选择的土地方格之间不能相邻(行和列)。

思路:

1、首先计算出每一行所能表示的状态上限,即二进制上限,并储存所有状态/方案;

2、输入矩阵。

3、处理状态转移的初始状态,即将第一行所有可行方案全部赋值为1,代表有一种方案可行;

ps:可行判断中用位运算&,需要注意的是,在这里我们将要比较的两组状态的其中一组做取反运算,因为单纯的正向比较无法完全区分可行方案与不可行方案。

4、从第二行开始状态转移,转移条件,当前行的某个可行方案,在上一行某可行方案下仍可行。即两个状态的十进制数进行位运算,结果必须为0。

5、最后一行dp值相加,输出最后结果。

AC代码:

#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[11010];
int dp[20][11010];//数据范围要注意,往大了开
int r[110];
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        int k=0;
        memset(a,0,sizeof(a));
        for(int i=0;i<(1<<m);++i)
        {
            if(!(i&(i<<1)))//预处理,筛选出所有可能的方案;
                a[++k]=i;
        }
        memset(r,0,sizeof(r));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;++i)
        {
            r[i]=0;
            for(int j=1;j<=m;++j)
            {
                bool x;
                cin>>x;
                if(x)r[i]+=(1<<(m-j));
            }
        }

        for(int i=1;i<=k;++i)//确定初始状态
        {
            if(!(a[i]&(~r[1])))//技巧:取反运算
            {
                dp[1][i]=1;
                //cout<<"1"<<endl;
            }
        }

        for(int i=2;i<=n;++i)//状态转移
        {
            for(int j=1;j<=k;++j)
            {
                if(!(a[j]&(~r[i])))
                {
                    for(int l=1;l<=k;++l)
                    {
                        if((a[j]&a[l])==0&&(a[l]&(~r[i-1]))==0)
                        {
                            dp[i][j]=(dp[i][j]+dp[i-1][l])%100000000;
                        }
                    }
                }
            }
        }
        long long ans=0;
        for(int i=1;i<=k;++i)ans=(ans+dp[n][i])%100000000;
        cout<<ans<<endl;

    }
    return 0;
}

状压dp的位运算理解了一下午。。。

The end;

猜你喜欢

转载自blog.csdn.net/qq_41661919/article/details/81115423