2020.02.12日常总结兼状压dp略讲(上)

状压dp \color{green}{\text{状压dp}}

状压dp是一种很重要的 dp \text{dp} ,其基本思路是利用二进制,简化我们状态的定义。

为了更好的理解状压,我们需要先来看看C++中的二进制运算:

  • &:二进制按位与运算符,格式为a&b,如果 a a b b 的二进制的同一位置上的数码都是 1 1 ,那么答案的该位数码也是 1 1 ,否则就是 0 0 。例如, ( 3 ) 10 & ( 6 ) 10 = ( 011 ) 2 & ( 110 ) 2 = ( 010 ) 2 = ( 2 ) 10 (3)_{10} \& (6)_{10}=(011)_2 \& (110)_2=(010)_2=(2)_{10}
  • |:二进制按位或运算符,格式为a|b,如果 a a b b 的二进制的同一位上的数码都是 0 0 ,那么答案的该位数码也是 0 0 ,否则就是 1 1 。例如: ( 6 ) 10 ( 12 ) 10 = ( 0110 ) 2 ( 1100 ) 2 = ( 1110 ) 2 = ( 14 ) 10 (6)_{10} | (12)_{10}=(0110)_2 | (1100)_2=(1110)_2=(14)_{10}
  • <<:这不是输出的符号吗?其实它还有另一个意思:左移运算符。格式:a<<b。就是把一个数的二进制的最高的 b b 位删了,在最低位加上 b b 0 0 ,例如 ( 3 ) 10 < < 1 = ( 011 ) 2 = ( 110 ) 2 = ( 6 ) 10 (3)_{10}<<1=(011)_2=(110)_2=(6)_{10} 。由此可见,一般而言, a < < b = a × 2 b a<<b=a \times 2^b ,只不过运算使得更快。
  • >>:它与左移运算符类似,叫右移运算符,操作和左移差不多,只不过是把最低的 b b 位删了,在最高位加上 b b 0 0 而已,一般而言, a > > b = a 2 b a>>b=\lfloor \dfrac{a}{2^b} \rfloor
  • ^:二进制按位异或运算符,格式为a^b,如果 a a b b 二进制的同一位不同时为 1 1 0 0 ,那么答案的该位就是 1 1 ,否则为 0 0 ,例子就不举了,值得一提的是, a b a & b = a a | b-a \& b= a ^ b b

今天,我们就讲到这里,明天我们再讲。


例题——洛谷P2157   学校食堂 \color{green}{\text{例题——洛谷P2157\ \ \ 学校食堂}}

\color{blue}{【题目链接】:} 题目链接

\color{blue}{【思路】:} f ( i , j , k ) f(i,j,k) 表示第 i 1 i-1 个人已经打完饭,第 i i 到第 i + 7 i+7 个人是否打完饭的状态为 j j ,且上一个打饭的人是 i + k i+k 的最小花费。转移看代码。

\color{blue}{【代码】:}

int f[1010][16][300];
int T[1010],B[1010],n;
int test_number,inf;
inline int cost(int a,int b){
	return (T[a]|T[b])-(T[a]&T[b]);
}
void ckmin(int &a,int b){a=min(a,b);}
int main(){
	freopen("t1.in","r",stdin);
	scanf("%d",&test_number);
	while (test_number--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
			scanf("%d%d",&T[i],&B[i]);
		memset(f,127,sizeof(f));
		inf=f[1][1][1];f[1][7][0]=0;
		for(int i=1;i<=n;i++)
			for(int j=0;j<256;j++)
				for(int k=-8;k<=7;k++)
					if (f[i][k+8][j]!=inf){
						if (j&1) ckmin(f[i+1][k+7][j>>1],f[i][k+8][j]);
//						如果第i个人已经打完饭了,直接转移至下一个人
						if ((j&1)==0){//第i个人没吃 
							register int lir=inf;
							for(int h=0;h<=7;h++)
								if (!((j>>h)&1)){
									if (i+h>lir) break;
									ckmin(lir,i+h+B[i+h]);
									ckmin(f[i][h+8][j|(1<<h)],f[i][k+8][j]+(i+k?cost(i+k,i+h):0));
								}
						} 
					}
		register int res=inf;
		for(int k=-8;k<=0;k++)
			res=min(res,f[n+1][k+8][0]);
		printf("%d\n",res);
	}
	return 0;
}
发布了103 篇原创文章 · 获赞 4 · 访问量 6727

猜你喜欢

转载自blog.csdn.net/ZHUYINGYE_123456/article/details/104277584
今日推荐