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\n", ans); } return 0; }
想的太多,做的太少。