2020.02.12日常總結兼狀壓dp略講(上)

狀壓dp\color{green}{\text{狀壓dp}}

狀壓dp是一種很重要的dp\text{dp},其基本思路是利用二進制,簡化我們狀態的定義。

爲了更好的理解狀壓,我們需要先來看看C++中的二進制運算:

  • &:二進制按位與運算符,格式爲a&b,如果aabb的二進制的同一位置上的數碼都是11,那麼答案的該位數碼也是11,否則就是00。例如,(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,如果aabb的二進制的同一位上的數碼都是00,那麼答案的該位數碼也是00,否則就是11。例如:(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。就是把一個數的二進制的最高的bb位刪了,在最低位加上bb00,例如(3)10<<1=(011)2=(110)2=(6)10(3)_{10}<<1=(011)_2=(110)_2=(6)_{10}。由此可見,一般而言,a<<b=a×2ba<<b=a \times 2^b,只不過運算使得更快。
  • >>:它與左移運算符類似,叫右移運算符,操作和左移差不多,只不過是把最低的bb位刪了,在最高位加上bb00而已,一般而言,a>>b=a2ba>>b=\lfloor \dfrac{a}{2^b} \rfloor
  • ^:二進制按位異或運算符,格式爲a^b,如果aabb二進制的同一位不同時爲1100,那麼答案的該位就是11,否則爲00,例子就不舉了,值得一提的是,aba&b=aa | b-a \& b= a ^ bb

今天,我們就講到這裏,明天我們再講。


例題——洛谷P2157   學校食堂\color{green}{\text{例題——洛谷P2157\ \ \ 學校食堂}}

\color{blue}{【題目鏈接】:} 題目鏈接

\color{blue}{【思路】:}f(i,j,k)f(i,j,k)表示第i1i-1個人已經打完飯,第ii到第i+7i+7個人是否打完飯的狀態爲jj,且上一個打飯的人是i+ki+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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章