hdu 4539 郑厂长系列故事——排兵布阵 (状态压缩dp)

本文介绍了一个使用二维动态规划解决士兵在战场上最优布阵的问题。通过定义状态转移方程并利用矩阵来存储中间结果,实现了在给定战场地图上的最大士兵部署数量计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

#include<stdio.h>
#include<string.h>

int dp[110][200][200];// dp[i][j][k] 存第i行 状态为state[j] 上一行状态为state[k] 所能安排士兵的最大值
int num[200];// 存合法状态对应的士兵数
int state[200]; // 存行内不冲突的合法状态
int map[110];// 用二进制按行存图
int limit;// dp上界
int size;// 合法状态数
int n,m;

int get(int x)// 计算状态x  包含1的个数
{
    int ans=0;
    while(x>0)
    {
        ans+=x%2;
        x=x/2;
    }
    return ans;
}

void in()// 把行内不冲突的合法状态存到state中
{
    int i;
    size=0;
    limit=1<<10;
    for(i=0;i<limit;i++)
    {
        if((i&(i<<2))==0)
        {
            num[size]=get(i);
            state[size++]=i;
        }

    }
    state[size++]=limit;
}

void init()
{
    limit=1<<m;
    memset(dp,0,sizeof(dp));
    memset(map,0,sizeof(map));
    int i,j,x;
    for(i=1;i<=n;i++)// 输入图  按行二进制存图
    {
        for(j=0;j<m;j++)
        {
            scanf("%d",&x);
            map[i]=(map[i]|(x<<j));
        }
    }
    
       for(i=0;state[i]<limit;i++)// 初始化第一行 第0行初始化为0用来解决n==1的情况
        {
            if((state[i]&map[1])!=state[i])continue;
            dp[1][i][0]=num[i];
        }

}

int solve()
{
    int i,j,k,l;

    for(i=2;i<=n;i++)// 从第二行开始向下dp
    {
        for(j=0;state[j]<limit;j++)// 枚举第i行的合法状态
        {
            if((state[j]&map[i])!=state[j])continue;// 状态state[j]必须是map[i]的子集  即状态state[j]的每个士兵必须安排在map[i]中为1的位置
            for(k=0;state[k]<limit;k++)
            {
               if((state[k]&map[i-1])!=state[k])continue;
               if((state[k]&(state[j]<<1))!=0)continue;// 判断当前行和上一行的状态是否冲突
               if((state[k]&(state[j]>>1))!=0)continue;
               for(l=0;state[l]<limit;l++)
               {
                 if((state[l]&map[i-2])!=state[l])continue;
                 if((state[k]&(state[l]<<1))!=0)continue;// 判断上一行和上上行是否冲突
                 if((state[k]&(state[l]>>1))!=0)continue;
                 if((state[l]&state[j])!=0)continue;// 判断当前行和上上行是否冲突
                 if(dp[i-1][k][l]+num[j]>dp[i][j][k])dp[i][j][k]=dp[i-1][k][l]+num[j];// dp[i][j][k] 存所有与之不冲突的dp[i-1][k][l]+num[j]的最大值

               }
            }
        }
    }

    int ans=0;
    for(i=0;state[i]<limit;i++)//遍历最后一行的所有状态 最大值即为答案
        for(j=0;state[j]<limit;j++)
        {
        if(dp[n][i][j]>ans)
            ans=dp[n][i][j];
        }
        return ans;
}
int main()
{
    in();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0||m==0)
        {
            printf("0\n");
            continue;
        }

        init();
        
        int ans=solve();
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值