| Time Limit: 2000MS | Memory Limit: 65536K | |
| Total Submissions: 16310 | Accepted: 8613 |
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
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
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
Hint
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经典题,dp[i][j]表示前i行状态为j的合法方案数,把j想象成一个M位的二进制数,每一位的0表示不放牧,1表示放牧,那么我们首先判断j这个状态本身是否合法(存在两个相连点的放牧或者有一个点本身不能放牧但是这个状态表示这里放牧),如果不合法则dp[i][j] = 0,如果合法,我们从i的前一行的所有合法状态进行转移,但是并不是所有的状态多可以转移过来,只有与当前行的状态j相容才能转移过来,也就是不会出现对于某一位在一列的出现都放牧的情况(不满足不能相连放牧的要求)。
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const LL mod = 1e9;
int N, M;
LL dp[20][5000];
int s[20][20];
int term[20];
int temp[20];
void init()
{
memset(dp, 0, sizeof(dp));
}
bool judge(int row, int x1, int x2)
{
//先判断x1状态是否合法
int cnt1 = M;
for(int j = 0; j < M; j++)
{
int num = (x1>>j)&1;
term[cnt1--] = num;
}
for(int j = 1; j <= M; j++)
{
if(s[row][j] == 1 && term[j] == 0)
{
return false;
}
}
for(int j = 1; j < M; j++)
{
if(term[j] == 0) continue;
else
{
if(s[row][j] == 1) continue;
else
{
if(s[row][j + 1] == 1) continue;
else if(term[j + 1] == 1)
{
return false;
}
}
}
}
int cnt2 = M;
for(int j = 0; j < M; j++)
{
int num = (x2>>j)&1;
temp[cnt2--] = num;
}
for(int j = 1; j <= M; j++)
{
if(term[j] == 1 && temp[j] == 1)
{
if(s[row][j] == 1 || s[row - 1][j] == 1) continue;
else return false;
}
}
return true;
}
int main()
{
while(~scanf("%d%d", &N, &M))
{
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= M; j++)
{
scanf("%d", &s[i][j]);
if(s[i][j]) s[i][j] = 0;
else s[i][j] = 1;
}
}
init();
int cnt;
for(int i = 0; i < (1<<M); i++)
{
dp[1][i] = 1;
cnt = M;
for(int j = 0; j < M; j++)
{
int num = (i>>j)&1;
term[cnt--] = num;
}
for(int j = 1; j <= M; j++)
{
if(s[1][j] == 1 && term[j] == 0)
{
dp[1][i] = 0;
break;
}
}
for(int j = 1; j < M; j++)
{
if(term[j] == 0) continue;
else
{
if(s[1][j] == 1) continue;
else
{
if(s[1][j + 1] == 1) continue;
else if(term[j + 1] == 1)
{
dp[1][i] = 0;
break;
}
}
}
}
}
for(int i = 2; i <= N; i++)
{
for(int j = 0; j < (1<<M); j++)
{
for(int k = 0; k < (1<<M); k++)
{
if(judge(i, j, k)) dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
}
}
}
LL sum = 0;
for(int i = 0; i < (1<<M); i++)
{
sum = (sum + dp[N][i]) % mod;
}
printf("%I64d\n", sum);
}
return 0;
}

本文介绍了一种利用状态压缩动态规划(状压DP)的经典算法来解决牧場种植玉米的问题,确保种植区域不相邻且避开不肥沃的土地。通过详细解析代码和算法流程,展示了如何计算所有可能的种植方案。
1078

被折叠的 条评论
为什么被折叠?



