HYSBZ 1151 动物园zoo - 状压dp

9 篇文章 0 订阅

题目描述

题目大意:

N个动物围成一个环,有K个小朋友,每个小朋友可以看到五个连续的动物,每个小朋友都有自己喜欢或讨厌的动物,当有一个自己讨厌的动物被移走或能看到一个自己喜欢的动物时,这个小朋友就会高兴。求最优的移走动物的方案,使得最多的小朋友高兴。

分析:

dp[i][S]:处理到第i个动物,i~i-3的动物移动与否的状态为S。
dp[i+1][S]=max{dp[i+1][newS],dp[i][S]+Influence} (有移动第i+1个或者不移动两种选择)
Influence:在newS下开心的children数量

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#include<vector>
#define MAXN 10000
#define MAXC 50000
#define MAXS 32
const int S=(1<<4)-1;

int n,c,fear[100],love[100],dp[MAXC+10][MAXS*2+10],happy[MAXC+10][MAXS+10],ans;

void prepare(int st)
{
    bool p,q;
    for(int s=0;s<=(1<<5)-1;s++){
        p=q=false;
        for(int j=1;j<=fear[0];j++)
            if(!(s&(1<<fear[j]))){
                p=true;
                break;
            }
        for(int j=1;j<=love[0];j++)
            if(s&(1<<love[j])){
                q=true;
                break;
            }
        if(p||q)
            happy[st][s]++;
    }
} // happy[start_pos][start_pos~5->s]
void read()
{
    int pos;
    scanf("%d%d",&n,&c);
    for(int i=1;i<=c;i++){
        scanf("%d%d%d",&pos,&fear[0],&love[0]);
        for(int j=1;j<=fear[0];j++){
            scanf("%d",&fear[j]);
            fear[j]=(fear[j]-pos+n)%n;
        }
        for(int j=1;j<=love[0];j++){
            scanf("%d",&love[j]);
            love[j]=(love[j]-pos+n)%n;
        }
        prepare(pos);
    }
}
void DP(int st)
{
    memset(dp,-1,sizeof dp);
    dp[4][st]=0;
    for(int i=4;i<n;i++){
        for(int s=0;s<=S;s++){
            if(dp[i][s]==-1)
                continue;
            for(int p=0,k;p<=1;p++){
                k=((s&(S^1))>>1)|(p*(1<<3));
                dp[i+1][k]=max(dp[i+1][k],dp[i][s]+happy[i-3][s|(p*(1<<4))]);
            }
        }
    }
    for(int s=0,k;s<=S;s++){
        k=s|((st&1)*(1<<4));
        dp[n][s]+=happy[n-3][k];
        k=((s&(S^1))>>1)|((st&3)*(1<<3));
        dp[n][s]+=happy[n-2][k];
        k=((s&(S^3))>>2)|((st&7)*(1<<2));
        dp[n][s]+=happy[n-1][k];
        k=((s&(1<<3))>>3)|(st<<1);
        dp[n][s]+=happy[n][k];
        ans=max(ans,dp[n][s]);
    }
}
void workout()
{
    for(int s=0;s<=S;s++)
        DP(s);
    printf("%d\n",ans);
}
int main()
{
    read();
    workout();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值