简单状态压缩 nyoj 81 炮兵阵地

#include<stdio.h>
#include<string.h>
int n,m,I;
int dp[105][105][105],s[105],ss[105];
int max(int a,int b)
{
    return a>b?a:b;
}
int check(int date)
{
    if(date&date<<1)//判断是否有两个1相邻
        return 0;
    if(date&date<<2)//判断是否有两个1相间
        return 0;
    return 1;
}
int count(int date)
{
    int ans=0;
    while(date!=0)
    {
        if((date&1)==1)//判断有几个1;
            ans++;
        date/=2;
    }
    return ans;
}
void init()
{
    int i;
    for(i=0; i<(1<<m); i++)//判断0到1<<m的范围内所有可能放的情况即不管是否与地图矛盾
        if(check(i))//只要放了炮这两个炮在同一行攻击不到的话就存到s数组内
        {
            s[I]=i;
            ss[I++]=count(i);//count(i)表示不管地图的情况下在一行中的状态为i是的跑的个数即1的个数存放到ss[]数组内
        }
}
int main()
{
    int map[105],i,j,k,r,t;
    char c;
    scanf("%d",&t);
    while(t--)
    {

        memset(map,0,sizeof(map));//map数组存放的是每一行的压缩状态
        memset(dp,-1,sizeof(dp));//dp[i][j][k]  i表示当前行j表示当前行的状态,k表示上一行的状态
        scanf("%d%d",&n,&m);
        if(m==0&&n==0)
        {
            printf("0\n");
            continue;
        }
        for(i=0; i<n; i++)//如图中第二行,m=4,i=1,map[1]=0,当j= 2时c=H,1<<(m-j-1)为2,2|map[1]=2;
        {                   //当j=3时1<<(m-j-1)为1,这时map[1]=2,map[1]|1相当于1|2等于3,map[1]z最终结果为3,二级制为11,
            getchar();//用1表示不能放,就把这一行的状态压缩成3
            for(j=0; j<m; j++)
            {
                scanf("%c",&c);
                if(c=='H')
                    map[i]=map[i]|(1<<(m-j-1));
            }
        }
        I=0;
        init();
        for(i=0; i<I; i++)
        {
            if((s[i]&map[0])==0)//判断是否与地图矛盾
                dp[0][i][0]=ss[i];
        }
        for(i=0; i<I; i++)
        {
            if((s[i]&map[1])==0)//判断是否与地图矛盾
            {
                for(j=0; j<I; j++)
                    if((s[i]&s[j])==0)//判断是否与上一行矛盾
                        dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+ss[i]);
            }
        }
        for(r=2; r<n; r++)//r表示行
        {
            for(i=0; i<I; i++)//第r行的状态
                if((s[i]&map[r])==0)//第r行的状态是否与地图矛盾
                {
                    for(j=0; j<I; j++)//第r-1行的状态
                        if((s[j]&map[r-1])==0&&(s[i]&s[j])==0)//第r-1行的状态是否与地图矛盾且是否与r行的状态矛盾
                        {
                            for(k=0; k<I; k++)//第r-2行的状态
                                if((s[k]&map[r-2])==0&&(s[k]&s[i])==0)//是否与地图矛盾且判断是否与第r行的状态矛盾
                                    dp[r][i][j]=max(dp[r][i][j],dp[r-1][j][k]+ss[i]);
                        }
                }
        }
        int ans=0;
        for(i=0; i<I; i++)//找出最后一行的状态中最大的能放炮的个数
            for(j=0; j<I; j++)
                if(dp[n-1][i][j]>ans)
                    ans=dp[n-1][i][j];
        printf("%d\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值