NKOJ P1184【NOI2001 Day2 T2】炮兵阵地 (状压DP)
司令部的将军们打算在 的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。
在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);
一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
输入格式
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。
N≤100;M≤10。
输出格式
仅在第一行包含一个整数K,表示最多能摆放的炮兵部队的数量。
样例输入
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
样例输出
6
来源 NOI2001
关于此状态后效性的问题:
若定义f[i][j] i 行状态为j
枚举i-1 行的最优和 i-2 行的最优不是能互推的 有后效性
但是 f[i][j][k] i行 状态 j i-1行 状态 k f[i-1][k][o] 状态一定 只用加1 个变量 所以无后效性
code:
1 // 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 int f[101][80][80]; 7 int mapp[202]; 8 int tot; 9 int n,m; 10 int now[101]; 11 int all; 12 int ans=0; 13 void dp() 14 { 15 int sum=0; 16 for(int i=1;i<=n;i++) 17 for(int j=1;j<=tot;j++) 18 { 19 if(((mapp[j]&now[i])==mapp[j])&&(((mapp[j]<<1)&mapp[j])==0)&&(((mapp[j]<<2)&mapp[j])==0)) 20 { 21 sum=0; 22 for(int z=1;z<=m;z++) 23 { 24 if(mapp[j]&(1<<z-1)) 25 { 26 sum++; 27 } 28 } 29 for(int k=1;k<=tot;k++) 30 { 31 if(((mapp[k]&mapp[j])==0)&&((now[i-1]&mapp[k])==mapp[k])) 32 { 33 for(int o=1;o<=tot;o++) 34 { 35 if(((mapp[j]&mapp[o])==0)&&(f[i-1][k][o]+sum>f[i][j][k]||(f[i][j][k]==-1))) 36 f[i][j][k]=f[i-1][k][o]+sum; 37 } 38 } 39 } 40 } 41 } 42 43 } 44 45 int main() 46 { 47 cin>>n>>m; 48 char x; 49 all=(1<<m)-1; 50 for(int i=1;i<=n;i++) 51 for(int j=1;j<=m;j++) 52 { 53 cin>>x; 54 if(x=='P') 55 { 56 now[i]|=(1<<m-j); 57 } 58 } 59 memset(f,-1,sizeof(f)); 60 61 for(int i=0;i<=all;i++) 62 { 63 if((i&(i<<2))==0&&(((i&(i<<1))==0))) 64 { 65 mapp[++tot]=i; 66 } 67 } 68 f[0][1][1]=0; 69 dp(); 70 for(int i=1;i<=tot;i++) 71 for(int k=1;k<=tot;k++) 72 { 73 ans=max(ans,f[n][i][k]); 74 } 75 printf("%d",ans); 76 }
刀剑映出了战士的心。而我的心,漆黑且残破