天生我材必有用,千金散尽还复来。 仰天大笑出门去,我辈岂是蓬蒿人。 大鹏一日同风起,扶摇直上九万里。 十步杀一人,千里不留行。 事了拂衣去,深藏身与名。 安能摧眉折腰事权贵,使我不得开心颜! 且乐生前一杯酒,何须身后千载名? 愿将腰下剑,直为斩楼兰。
 

POJ 3254

 

Corn Fields
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 15745   Accepted: 8275

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

 
 

今天刚学状压dp,碰到这个题,下午看了好几个博客,终于有了点头绪。(大佬的博客注释都比较少。。所以我写了比较多的注释)

利用二进制与十进制的关系,降低维度。像这个题,每行的土地都只有0 1两种状态,可以把这一行的状态用一个十进制数表示。这应该就是一种状态压缩了~。
 
题解:我们称一行中没有相邻的1的状态为好状态。。(不要在意名字)
先将每行中所有的好状态找出来,用十进制表示,{   2的N次方 = (1<<(N-1) )   }
void getvalid()///得到所有可行的状态
{
    for(int i = 0 ; i < (1<<n);i++){
        if(!(i&(i<<1))){///如果这个数的二进制形式没有相邻的1,会将这个数记录下来
            st[num++] = i;
        }
    }
}

判断理想是否符合现实(该状态所对应的各个位置是否是肥沃土地)。

bool judge(int p,int q)///判断该状态是否符合土地状况,也就是说,想种东西的地方是不是肥沃
{
    if(!(st[p]&map[q])){///注意:!!这里土地状态map[q]是记录的不肥沃的土地,所以按位与后应为0,取非为1
        return true;    /// 换句话说 想法与实践比较,前者为想法,后者为实践,看是否可行
    }
    return false;
}

接下来更详细的在代码里都有了~~

#include<iostream>
#define MOD 100000000
using namespace std;
int dp[13][100005];///dp[i][j]表示第i行第j状态时的方案数
int st[10009];///一行中所有的可行的状态
int num;///记录状态数
int n,m;///m行n列
int s;///暂存单位土地的状态
int map[15];///十进制数记录每行的土地状态

void getvalid()///得到所有可行的状态
{
    for(int i = 0 ; i < (1<<n);i++){
        if(!(i&(i<<1))){///如果这个数的二进制形式没有相邻的1,会将这个数记录下来
            st[num++] = i;
        }
    }
}
bool judge(int p,int q)///判断该状态是否符合土地状况,也就是说,想种东西的地方是不是肥沃
{
    if(!(st[p]&map[q])){///注意:!!这里土地状态map[q]是记录的不肥沃的土地,所以按位与后应为0,取非为1
        return true;    /// 换句话说 想法与实践比较,前者为想法,后者为实践,看是否可行
    }
    return false;
}
int main()
{
    cin >> m >> n;
    for(int i = 1 ; i <= m ; i++){
        map[i] = 0;
        for(int j = 1 ; j <= n ; j++){
            cin >> s;
            if(!s){
                map[i] += (1<<(j-1));///将每行的不肥沃的土地记录下来
            }                       ///注意此处是j!!
        }
    }

    for(int i = 0 ; i < 13;i++){
        for(int j = 0 ; j < 100005;j++){
            dp[i][j] = 0;
        }
    }
    dp[0][0] = 1;///啥也不放时,算一种方案
    num = 0;
    getvalid();

    for(int i = 1 ; i <= m;i++){
        for(int j = 0; j < num ; j++){///j是这一行状态的编号
            if(judge(j,i)){
                for(int k = 0 ; k < num ; k++){///k是这一行的编号
                    if(judge(k,i-1)&&!(st[j]&st[k])){///如果上一行的k对应的状态是“理想”与“现实”相同的  &  &  并且这一行状态与上一行状态之间没有出现相同位都是1
                        dp[i][j] += dp[i-1][k];
                    }
                }
            }
        }
    }

    int sum = 0;
    for(int i = 0; i < num;i++){
        sum += dp[m][i];
        sum %= MOD;
    }
    cout << sum << endl;


    return 0;
}

转载请注明出处~~

感谢您的阅读~

 

 
posted @ 2017-07-27 16:31  gudy  阅读(116)  评论(0编辑  收藏  举报