种树(0183)
问题描述
Aconly有一块矩形的地,因为这块地里有很多石头,耕作很不方便,所以他打算在这块地上种一些果树。这块地用一个只含‘#’和‘*’的N*M的矩阵来表示,‘#’表示泥土,‘*’表示石头。当然有石头的地方是不能种树的,而且任意两棵树之间不能离得太近,表现在矩阵中就是不能上、下、左、右、左上、右上、左下、右下八个方向相邻。你的任务就是帮助Aconly算出这块地最多可以种多少棵树。
输入
有多组测试数据。每组测试数据以两个整数N和M开头,随后有N行只含‘#’和‘*’的字符,每行M个。 (1<=N<=100, 1<=M<=10)当M=N=0时表示输入结束。
输出
每组数据输出一个整数,表示Aconly最多可以在这块地里种多少棵树。每组输出数据占一行。
样例输入
5 4
####
**#*
##*#
####
##*#
0 0
样例输出
6
简单状压DP、代码还可以继续优化
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include <cmath> using namespace std; #define ll long long #define int2 unsigned int #define MOD (1<<32) #define INF 0x3f3f3f3f #define N 1024 int n,m; int a[N]; int dp[N][N]; //dp[i][j]表示第i行状态为j时的最大种树棵数 char mpt[N][N]; bool judge(int row,int sta) { if((a[row]&sta)!=sta) return 0; if(sta&(sta<<1)) return 0; return 1; } bool judge2(int r1,int r2) { if(r1&r2) return 0; if((r1<<1)&r2 || (r1>>1)&r2) return 0; return 1; } int cal1(int n) { int ret=0; while(n){ ret+=n%2; n>>=1; } return ret; } void solve() { int i,j,k; int MAX=1<<m; dp[0][0]=0; for(i=1;i<=n;i++){ for(j=0;j<MAX;j++){ if(!judge(i,j)) continue; for(k=0;k<MAX;k++){ if(!judge2(j,k)) continue; dp[i][j]=max(dp[i][j],dp[i-1][k]+cal1(j)); } } } int ans=0; for(i=n,j=0;j<MAX;j++) ans=max(ans,dp[i][j]); printf("%d ",ans); } int main() { while(scanf("%d%d",&n,&m),n||m) { memset(a,0,sizeof(a)); memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ char ch; scanf(" %c",&ch); if(ch=='#') a[i]=(a[i]<<1)+1; else a[i]=(a[i]<<1); } } solve(); } return 0; }