文章标题 POJ 1185 : 炮兵阵地 (状压DP)

来源:互联网 发布:网络就是个粪坑 编辑:程序博客网 时间:2024/06/01 08:00

题目链接

分析:首先我们可以先预处理一行中出所有状态中哪那些状态是可行的,即炮兵不会被放在另一个炮兵的射程内用each数组存储。然后同样预处理出地图每一行的状态,其中高地用1表示,用mp数组存储,这两个数组是我为了判断在第j行中第i个状态是否可行,即each[i]&mp[j],返回1表示有 冲突
然后我们用dp[I][j][k]来表示在第i行中的第j个状态与第n-1行中的第k个状态中炮兵的数量,然后预处理出第1,2行,然后就可以写出状态转移方程了
dp[I][j][k]=max(dp[I-1][k][kk])其中j表示第I行的状态,k表示第i-1行的状态,kk表示第i-2行的状态,且这三行中的状态与地图没有冲突,两两对应的状态也没有冲突。
代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <queue>#include <set>#include <map>#include <algorithm>#include <math.h>#include <vector>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e5+10;char ch[105][15];ll dp[105][65][65];int each[65];//each[i]表示每一行中合理的不产生冲突的状态int sum[65];//表示第i种状态中炮兵(即1)的数量 int mp[105];//表示每一行中地图的状态,高地(H)为1 int n,m;bool judge(int s){//判断s这个状态是否符合题意(即不互相攻击)     for (int i=0;i<m;){        if (s&(1<<i)){            if (i+1<m&&(s&(1<<(i+1))))return false;            if (i+2<m&&(s&(1<<(i+2))))return false;            i+=2;         }else i++;    }    return true;}bool judge_map(int row,int s){//s这个状态在第row行是否可行,返回1表示不可行,因为炮兵放在高地了     return (mp[row]&s); }int main(){    while (scanf ("%d%d",&n,&m)!=EOF){        for (int i=1;i<=n;i++){            scanf ("%s",ch[i]+1);            mp[i]=0;            for (int j=1;j<=m;j++){                if (ch[i][j]=='H'){                    mp[i]+=(1<<(j-1));                }            }         }        memset (dp,0,sizeof (dp));        int cnt=0;        for (int i=0;i<(1<<m);i++){//预处理出每一行可行的状态数             if (judge(i))each[cnt++]=i;        }        for(int i=0;i<cnt;i++){//与处理出每一种状态的炮兵数             sum[i]=0;            for (int j=0;j<m;j++){                if (each[i]&(1<<j)){                    sum[i]++;                }            }        }         for(int i=0;i<cnt;i++){//预处理第一行             if (!judge_map(1,each[i])){                dp[1][i][0]=sum[i];            }        }         for(int i=0;i<cnt;i++){//第二行             if (judge_map(2,each[i]))continue;            for (int j=0;j<cnt;j++){                if (!(each[i]&each[j])){//这两行对应的状态没有冲突                     dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+sum[i]);                }            }        }         for (int i=3;i<=n;i++){            for (int j=0;j<cnt;j++){//第i行的状态                 if (judge_map(i,each[j]))continue;                for (int k=0;k<cnt;k++){//第n-1行的状态                     if (judge_map(i-1,each[k])) continue;                    if ((each[j]&each[k]))continue;//i行与 i-1行冲突                    for (int kk=0;kk<cnt;kk++){//第n-2行的状态                         if (judge_map(i-2,each[kk]))continue;                        if (each[k]&each[kk])continue;//i-1行与i-2冲突                        if (each[j]&each[kk])continue;//i行与i-2行冲突                        dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][kk]+sum[j]);                     }                 }            }        }         ll ans=0;        for (int i=0;i<cnt;i++){            for (int j=0;j<cnt;j++){                ans=max(ans,dp[n][i][j]);            }        }         printf ("%lld\n",ans);    }    return 0;}
原创粉丝点击