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

来源:互联网 发布:python for none 编辑:程序博客网 时间:2024/05/21 10:30

题目链接:点击打开链接

#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;}


0 0