这~~绝对是最好调~~的错代码!!十分感谢~

P2704 [NOI2001] 炮兵阵地

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,所以帮你调出来了

在你的 pre函数里,更新时要取max,不能直接赋值的

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到了! 谢谢


|