1. 程式人生 > 實用技巧 >【解題報告】P1896 [SCOI2005]互不侵犯

【解題報告】P1896 [SCOI2005]互不侵犯

我悶今天的目的就是通過這道題初步理解一下狀態壓縮類動態規劃

首先我們先來介紹一下定義,所謂狀態壓縮類動態規劃,顧名思義,這是以集合資訊為狀態的特殊的動態規劃問題。主要有傳統集合動態規劃和基於連通性狀態壓縮的動態規劃兩種。

因為某些動態規劃的需求資訊量非常的大,並且我們為每一個資訊開一維陣列這樣的做法是非常不現實的,所以說我們的狀態壓縮類動態規劃也就應運而生了!

預備知識

位操作是一種非常快的基本運算:有左移、右移、與、或、非等運算。

左移:左移一位相當於某數乘2.

右移:右移一位相當於某數除以2.

與運算:按位進行“與”運算,兩數同一位都為1時結果為1,否則為0,例如:101&110=100。

或運算

:按位進行“或”運算,兩數同一位都為0時結果為0,否則為1,例如:101|110=111。

非運算:按位取反。0變1,1變0,例如:~101=010。

於是學會了上面這些操作,我們就可以幹一些比較簡單的事情了。

  • 判斷第i位是否為0,(S&(1<<i))==0,意思是將1左移i位與S進行與運算後,看結果是否為0.

  • 將第i位設定為1,S|(1<<i),意思是將1左移i位與S進行或運算.

  • 將第i位設定為0,S&~(1<<i),意思是S與第i位為0,其餘位為1的數進行與運算。

例如:S=1010101,i=5.

S&(1<<i):1010101&0100000=0000000.

S|(1<<i):1010101|0100000=1110101.

S&~(1<<i):1010101&1011111=1010101.

這裡在講程式碼前我覺得還是有必要在科普一個知識,就是關於判斷一個整數的二進位制數裡有幾個1。這裡我們需要用一個騷騷的操作。雖然我本人也沒有看懂。

int func(unsigned int n){
  int count=0;
  while(n>0){
    n=n&(n-1);
    count++;
  }
  return count;
}

這裡轉載一段:

比如輸入10,n-1=9,1010(10的二進位制)&1001(9的二進位制),得到一個1000(8的二進位制),n=8,count++=1
第二次迴圈,n-1=7,8&7=0,count++=2;跳出迴圈,返回count,也就是說10的二進位制裡面有2個1。。。。

壓行程式碼:

LL func(LL n){LL count=0;while(n>0){n=n&(n-1);count++;}return count;}

所以說大家應該也都懂了應該怎麼寫了!!!

程式碼如下:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL avai[2000],gs[2000],cnt=0,n,yong,f[10][2000][100],ans;
LL func(LL n){LL count=0;while(n>0){n=n&(n-1);count++;}return count;}
bool check(LL i){return (i&(i>>1))==0&&(i&(i<<1))==0;}
int main()
{
    scanf("%lld%lld",&n,&yong);
    for(LL i=0;i<(1<<n);++i)if(check(i))avai[++cnt]=i,gs[cnt]=func(i);//預處理所有的狀態,avai記錄的是狀態,而ge記錄的是當前狀態所用的國王的個數 
    for(LL i=1;i<=cnt;i++)f[1][i][gs[i]]=1;//第一層的所有狀態均是有1種情況的
    for(LL i=2;i<=n;i++)
		for(LL k=1;k<=cnt;k++)
			for(LL j=1;j<=cnt;j++){//列舉i、j、k,j,k在迴圈中沒有特殊要求,反著寫也可以 
        		if((avai[j]&avai[k])||((avai[j]<<1)&avai[k])||((avai[j]>>1)&avai[k]))continue;//排除不合法國王情況
        		for(LL s=yong;s>=gs[j];s--)f[i][j][s]+=f[i-1][k][s-gs[j]];
			}//列舉s,計算f[i][j][s]
	for(LL i=1;i<=cnt;i++)ans+=f[n][i][yong];
    printf("%lld",ans);
    return 0;
}