Virtualtan @ 2019-09-10 22:09:08
感谢光临此贴 由于楼主太菜了,还是没过这个状压DP
为了方便您的差错,楼主把调试代码都没删
万分感谢
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m,debug;
int f[3][60][60];//f[i][st1][st2]:当前为第i行,第i行状态为st[st1], 第i-1行状态为st[st2]时的最大方案数
//影响答案的只有三行
struct node{
int num, st[60];
int num_s[60];//状态st[i]所拥有的士兵个数为num_s[i]
}can[100+9];
int getone(int x) {
int num = 0;
while(x) x -= x & -x, num++;
return num;
}
void getstate(int hang, int st) {
int num = 0;
for(int i = 0; i < (1<<m); i++) {
if( (i&(i<<1)) || (i&(i<<2)) || (i&(i>>1)) || (i&(i>>2)) || (i&st)) continue;
can[hang].st[++num] = i;
can[hang].num_s[num] = getone(i);
}
can[hang].num = num;
}
void init() {//get每行合法的情况
string s;
int t, tmp;
for(int i = 1; i <= n; i++) {
cin>>s;
t = 0;
for(int j = 0; j < m; j++) {
tmp = s[j]=='H' ? 1 : 0;
t = (t<<1)+tmp;//山地不放
}
// if(debug == 2) printf("第%d行的t值: %d\n", i, t);
getstate(i, t);
}
}
void pre() {//初始化一二行
for(int j = 1; j <= can[1].num; j++) f[1][j][0] = can[1].num_s[j];
for(int j = 1; j <= can[2].num; j++)
for(int k = 1; k <= can[1].num; k++) {
if(can[2].st[j]&can[1].st[k]) continue;
f[2][j][k] = can[2].num_s[j] + can[1].num_s[k];
}
}
int main() {
// freopen("02.in", "r", stdin);
// freopen("02.out", "w", stdout);
debug = 1;
scanf("%d%d",&n,&m);
init();
pre();
// if(debug == 1) {
// for(int i = 1; i <= n; i++) {
// printf("第%d行的合法情况如下, 共%d个合法情况\n",i, can[i].num);
// for(int j = 1; j <= can[i].num; j++) printf("士兵数:%d ; 状态: %d \n", can[i].num_s[j] ,can[i].st[j]);
// }
// }
for(int i = 3; i <= n; i++)
for(int j = 1; j <= can[i].num; j++)
for(int k = 1; k <= can[i-1].num; k++) {//士兵数从上往下只增不减,所以不用初始化f[i][j][k]
if(can[i].st[j]&can[i-1].st[k]) continue;//填表法
for(int up2 = 1; up2 <= can[i-2].num; up2++) {
if(can[i-2].st[up2]&can[i-1].st[k] || can[i-2].st[up2]&can[i].st[j]) continue;
f[i%3][j][k] = max(f[i%3][j][k], f[(i-1)%3][k][up2]+can[i].num_s[j]);
}
}
int ans = 0;
for(int j = 1; j <= can[n].num; j++)
for(int k = 1; k <= can[n-1].num; k++) {
if(can[n].st[j]&can[n-1].st[k]) continue;//???
ans = max(ans, f[n%3][j][k]);
}
printf("%d\n",ans);
//为什么只用前一个和当前的:我们只需要这样就可以表示出所有要用的状态了
return 0;
}
by zhy137036 @ 2019-09-13 11:54:15
帖子的标题是不能用Markdown的
by 世墨 @ 2019-09-19 08:59:20
不知道楼主还在不在,但看你还没AC,所以帮你调出来了
在你的
void pre() {
for(int j = 1; j <= can[1].num; j++) f[1][j][0] = can[1].num_s[j];
for(int j = 1; j <= can[2].num; j++)
for(int k = 1; k <= can[1].num; k++) {
if(can[2].st[j]&can[1].st[k]) continue;
f[2][j][k] = max(f[2][j][k],can[2].num_s[j] + can[1].num_s[k]);//我改了这里
}
}
还有,我顺手加了几个括号,如果这里改了没AC,可能是位运算没加括号,该加的括号都加上是个好习惯
by Virtualtan @ 2019-09-27 21:30:29
@世墨 感谢!! 虽然还是木有A...但是非常感谢您为我花时间
那个pre不就是初始化第二行吗?不需要写max吧,它好像并不会重复更新f[2][j][k]
的...
(抱歉,现在才看见....
by Virtualtan @ 2019-09-27 21:31:07
@zhy123456
嘘....
(好尴尬呀....
by Virtualtan @ 2019-09-27 21:53:22
@世墨
加括号的好习惯get到了! 谢谢