【计蒜客习题】灌溉机器人

问题描述


农田灌溉是一项十分费体力的农活,特别是大型的农田。蒜头君想为农民伯伯们减轻农作负担,最近在研究一款高科技——灌溉机器人。它可以在远程电脑控制下,给农田里的作物进行灌溉。
现在有一片 N 行 M 列的农田。农田的土壤有两种类型:类型 HH 和类型 PP,每一个格子上的土壤类型相同。其中类型 P 的土壤硬度较大,可以用来布置灌溉机器人,但是一个格子上只能布置一台。类型 H 的土壤不能布置灌溉机器人。一台灌溉机器人的灌溉区域如下图所示:

黄色表示灌溉机器人布置的格子,红色表示其灌溉区域,即四个方向上各外扩展两个格子。
蒜头君想在农田上尽可能多布置一些灌溉机器人,但是任意一台机器人不能在任意一台机器人的灌溉区域里,否则机器容易进水出故障。现在已知农田每个格子的土壤类型,请你来帮蒜头君计算一下,蒜头君最多能布置多少台灌溉机器人。


输入格式


输入第一行输入两个正整数N,M(N≤100,M≤10),表示农田的行和列。
接下来输入 N 行,每行输入连续的 M 个字符(P或者H),中间没有空格。表示农田每个格子上的土壤类型。


输出格式


输出一行,输出一个整数,表示最多能摆放的灌溉机器人的数量

样例输入

3 4
PHPP
PHPP
PHHP

样例输出

3


呃呃,一道状压DP入门题。

没什么好说的,注意先预处理一下,发现若要满足同一行不冲突,情况最多有60种。定义dp[i][j][k]表示处理到第i行,当前行选择方案为j,上一行选择方案为k时最多的摆放数量,这样就可以保证只需知道当前行的dp和上一行的dp就可以知道对当前行选择方案有影响的上一行和上上一行,转移方程显然是dp[i][j][k]=max{dp[i-1][k][l]+count(j)},count返回某一方案的机器人数量。再就是冲突时的判断需要写好。

 1 #include<cstdio>
 2 inline int max(int a,int b) {return a>b?a:b;}
 3 const int maxn=105,maxm=15;
 4 //经预先验证,满足同一行不冲突的情况最多有60种
 5 int n,m,map[maxn],state[65],cnt,dp[maxn][65][65],ans;
 6 bool judge1(int x) {
 7     return (x&(x>>1))==0&&(x&(x>>2))==0;
 8 }
 9 bool judge2(int i,int j) {
10     return (j|map[i])==map[i];
11 }
12 bool judge3(int x,int y) {
13     return (x&y)==0;
14 }
15 int count(int i) {
16     int c=0;
17     while(i) {
18         if(i&1) ++c;
19         i>>=1;
20     }
21     return c;
22 }
23 int main() {
24     scanf("%d%d",&n,&m);
25     for(int i=1;i<=n;++i) {
26         int si=0;char c;
27         for(int j=0;j<m;++j) {
28             while((c=getchar())=='
'||c==' '||c=='
');
29             if(c=='P') si|=(1<<j);
30         }
31         map[i]=si;
32     }
33     for(int i=0;i<(1<<m);++i) if(judge1(i)) state[++cnt]=i;
34     for(int i=1;i<=cnt;++i) if(judge2(1,state[i])) {
35         int cnt_i=count(state[i]);
36         for(int j=1;j<=cnt;++j) dp[1][i][j]=cnt_i;
37     }
38     for(int i=2;i<=n;++i)
39         for(int j=1;j<=cnt;++j) if(judge2(i,state[j])) {
40             int cnt_j=count(state[j]);
41             for(int k=1;k<=cnt;++k) if(judge2(i-1,state[k])&&judge3(state[j],state[k]))
42                 for(int l=1;l<=cnt;++l)
43                     if(judge2(i-2,state[l])&&judge3(state[k],state[l])&&judge3(state[j],state[l]))
44                         dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+cnt_j);
45         }
46     for(int i=1;i<=cnt;++i)
47         for(int j=1;j<=cnt;++j) ans=max(ans,dp[n][i][j]);
48     printf("%d",ans);
49     return 0;
50 }
AC代码
原文地址:https://www.cnblogs.com/Mr94Kevin/p/9635865.html