1. 程式人生 > 其它 >P2915 [USACO08NOV]Mixed Up Cows G 題解

P2915 [USACO08NOV]Mixed Up Cows G 題解

首先依然觀察到$N=16$,肯定是狀壓奶牛。

為了避免後效性,我們發現對於一個奶牛是否能在某個位置只和它前一個奶牛和後一個奶牛有關

因此我們可以設$f(i,state)$表示奶牛狀態為$state$(1為在序列中0為不在),當前以後排好隊的奶牛的最後一個為$i$的方案數

那麼$f(i,state)=\sum{f(j,state\oplus 1<<(i-1))}, i,j \in state$

主要提供一個轉移的方法

我們可以發現拓撲序應為$0000$ $0001$ $0010$ $0100$ $1000$ $0011$ $0110$ $0101$.......

也就是先一個$1$再兩個$1$....

實現起來比較困難

事實上我們可以直接從0自加到$2^n-1$,這樣也是滿足拓撲序的

程式碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 inline int r()
 8 {
 9     int s=0,k=1;char c=getchar();
10     while(!isdigit(c))
11     {
12         if(c=='-')k=-1;
13         c=getchar();
14 } 15 while(isdigit(c)) 16 { 17 s=s*10+c-'0'; 18 c=getchar(); 19 } 20 return s*k; 21 } 22 int n,m,a[101],f[66666][101];//狀態 最後一個 23 bool b[66666]; 24 signed main() 25 { 26 n=r();m=r(); 27 for(int i=1;i<=n;i++) 28 { 29 a[i]=r(); 30 } 31 for
(int i=1;i<=n;i++) 32 { 33 f[1<<(i-1)][i]=1; 34 } 35 for(int i=0;i<=(1<<n)-1;i++) 36 { 37 if(b[i])continue; 38 for(int j=1;j<=n;j++)//當前最後一個 39 { 40 if(!(i&(1<<(j-1))))continue; 41 for(int k=1;k<=n;k++)//前一個的最後一個 42 { 43 if(!(i&(1<<(k-1))))continue; 44 if(j==k)continue; 45 if(abs(a[j]-a[k])<=m)continue; 46 f[i][j]+=f[i^(1<<(j-1))][k]; 47 } 48 } 49 50 } 51 int ans=0; 52 for(int i=1;i<=n;i++) 53 { 54 ans+=f[(1<<n)-1][i]; 55 } 56 cout<<ans; 57 }
View Code