[状压dp] 动物园题解

Posted zero_orez6

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[状压dp] 动物园题解相关的知识,希望对你有一定的参考价值。

动物园

P2911 动物园 题解

题意

有N个成环形的房间,C个小朋友,对于每个小朋友他们能看到E - E+4共五个房间,每个小朋友有F个喜欢的房间和L个讨厌的房间,当满足以下两个条件其中之一时,小朋友就会开心:

  • 至少有一个他害怕的房间被移走;

  • 至少有一个他喜欢的房间没被移走。

可以移走若干个房间,问最多能令多少个小朋友开心。

分析

dp式

对于任一个小朋友能够看到的五个房间,我们用0和1来表示这个房间是否撤走,而每个小朋友能看到的5个房间恰好能够作为状压dp的变量,用一个五位的二进制数s来表示任一位置$ i - i+4 $的状态

用f[i][s]表示当$ i-i+4 这 五 个 房 间 的 状 态 为 s 时 , 能 够 最 多 让 多 少 小 朋 友 开 心 , 那 么 对 于 任 意 时 刻 的 f [ i ] [ s ] 肯 定 由 f [ i − 1 ] [ s ] 所 转 移 过 来 的 , 也 就 是 说 从 这五个房间的状态为s时,能够最多让多少小朋友开心,那么对于任意时刻的f[i][s]肯定由f[i-1][s]所转移过来的,也就是说从 sf[i][s]f[i1][s] (i-1) - (i+3) $的房间已经确定好了状态,只差i+4未确定状态,由此可以得出状态转移式为:

	f[i][s]=max(f[i-1][(s&15)<<1],f[i-1][(s&15)<<1|1])+sum[i][s]
    

其中sum[i][s]表示当i - i+4这五个房间的状态为s时能够使多少个小朋友开心。初始状态为 $ f[0][s]=0 $ ,s为当前所枚举的状态。

为什么是s&15呢 ?

因为从i-1 - i+3的房间已经确定好了状态,我们现在要确定第i+4位的状态,也就是取i-1 - i+3后四位的状态,15(10)=1111(2),通过&操作取后四位,再左移判断第i+4位。

sum[i][s]如何去求呢?

对于任一个小朋友,其输入为 $ E\\ F\\ L\\ x_1\\ x_2…\\ x_F \\ y_1\\ y_2\\ …\\ y_L $

我们用两个五位二进制数like和hate来表示当前小朋友所能够看到的房间$ E - E+4 的 状 态 s 但 注 意 此 题 目 所 有 房 间 成 环 形 , 在 处 理 时 的状态s 但注意此题目所有房间成环形,在处理时 s a-x $有可能为负数,所以应写成:

like=like|(1<<(a-x+n)%n)

在每一个小朋友的数据输入完后,枚举每个状态s

if((s&hate)||(~s&like)) sum[E][s]++;

表示若满足两个条件中的任一个,sum[E][s]++。

答案的统计

在dp的过程中,我们肯定先枚举第0位的状态,而f[i][s]表示当$ i-i+4 $这五个房间的状态为s时,能够最多让多少小朋友开心,所以答案最后为
$ ans=MAX_1 - n f[n][i] $

code

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+86,MAX=1e8+86;
int n,c,like,hate,sum[N][50];
int main()

	freopen("zoo.in","r",stdin);
	freopen("zoo.out","w",stdout);
	cin>>n>>c;
	for(int i=1;i<=c;i++)
	
		int x,y,z,a;
		like=0;hate=0;//初始化 
		cin>>x>>y>>z;
		for(int j=1;j<=y;j++)
		
			cin>>a;
			hate=hate|(1<<((a-x+n)%n));//处理五位二进制数hate 
		
		for(int j=1;j<=z;j++)
		
			cin>>a;
			like=like|(1<<((a-x+n)%n));//处理like 
		
		for(int j=0;j<(1<<5);j++)//枚举所有状态 
		
			if((j&hate)||(~j&like)) sum[x][j]++;//判断是否满足两个条件其中之一 
		
	
	int f[N][50],ans=0; 
	for(int i=0;i<(1<<5);i++)//枚举第0位的状态 
	
		memset(f[0],-1086,sizeof(f[0]));//将f[0][1~n]全部赋值为极小值 
		f[0][i]=0;//初始化f[0][i] 
		for(int j=1;j<=n;j++)
		
			for(int k=0;k<(1<<5);k++)
			
				f[j][k]=max(f[j-1][(k&15)<<1],f[j-1][(k&15)<<1|1])+sum[j][k];//dp式 
			
		
		ans=max(ans,f[n][i]);//更新答案 
	
	cout<<ans<<endl;
	return 0;





以上是关于[状压dp] 动物园题解的主要内容,如果未能解决你的问题,请参考以下文章

[APIO2007]动物园 --- 状压DP

bzoj1151: [CTSC2007]动物园zoo 状压dp

P3622 [APIO2007]动物园

[APIO2007]动物园

P3622 [APIO2007]动物园

题解codeforces 8c Looking for Order 状压dp