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

题目链接

分析:首先我们可以先预处理一行中出所有状态中哪那些状态是可行的,即炮兵不会被放在另一个炮兵的射程内用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;
}
发布了191 篇原创文章 · 获赞 1 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章